码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P3177 [HAOI2015]树上染色 |树形DP

时间:2020-06-16 23:21:34      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:子节点   stream   while   include   ios   tin   --   i++   输出   

题目描述

有一棵点数为 nnn 的树,树边有边权。给你一个在 \(0 \sim n\) 之内的正整数 \(k\) ,你要在这棵树中选择 \(k\) 个点,将其染成黑色,并将其他 的 \(n-k\) 个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的受益。问受益最大值是多少。

输入格式

第一行包含两个整数 \(n,k\)

第二到 \(n\) 行每行三个正整数 \(fr, to, dis\),表示该树中存在一条长度为 \(dis\) 的边 \((fr, to)\)。输入保证所有点之间是联通的。

输出格式

输出一个正整数,表示收益的最大值。


转移方程为dp[u][i] = max( dp[u][i], dp[u][i-j] + dp[v][j] + val )

其中v为u的子节点,j为在这个子节点中选择的黑色点的个数,val为这条边的贡献

val = j(k-j)w + (sz[v]-j)(n-k+j-sz[v])w

其中w为这条边的边权,n为总的节点数,k为总的需要选择的黑色节点数,sz[v]为以v为根的子树的节点数量

为了卡时限,可以尝试rand一个根,不过也有可能会变慢


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<ctime>
#include<queue>
#include<iostream>
#include<cmath>
#include<algorithm>
#define inf 1000000000
#define ll long long
#define int long long
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
const int N=2005;
int nxt[N<<1],head[N],go[N<<1],cost[N<<1],tot;
inline void add(int u,int v,int w){
	nxt[++tot]=head[u],head[u]=tot,go[tot]=v,cost[tot]=w;
	nxt[++tot]=head[v],head[v]=tot,go[tot]=u,cost[tot]=w;
}
int n,m,dp[N][N],siz[N];
inline void DP(int &u,int &v,int &w){
	for(int i=min(m,siz[u]);i>=0;i--)
	for(int j=0;j<=min(i,siz[v]);j++)
	if(~dp[u][i-j]){
		int val=w*(j*(m-j)+(siz[v]-j)*(n-m+j-siz[v]));
		dp[u][i]=max(dp[u][i],dp[u][i-j]+dp[v][j]+val);
	}
}
void dfs(int u,int fa){
	siz[u]=1,dp[u][0]=dp[u][1]=0;
	for(int i=head[u];i;i=nxt[i]){
		int v=go[i],w=cost[i];
		if(v==fa)continue;
		dfs(v,u);
		siz[u]+=siz[v];
		DP(u,v,w);
	}
}
signed main(){
	//srand(time(0));
	memset(dp,-1,sizeof(dp));
	n=read(),m=read();
	m=min(m,n-m);
	for(int i=1,u,v,w;i<n;i++){
		u=read(),v=read(),w=read();
		add(u,v,w);
	}
	int rt=1;
	dfs(rt,0);
	cout<<dp[rt][m]<<endl;
}

luogu P3177 [HAOI2015]树上染色 |树形DP

标签:子节点   stream   while   include   ios   tin   --   i++   输出   

原文地址:https://www.cnblogs.com/naruto-mzx/p/13149625.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!