[BZOJ4033][HAOI2015]树上染色 树形DP
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4033
我们考虑用$f[i][j]$记录以第$i$个节点为根的子树,把$j$个节点染成黑色对最终的答案的最大贡献。
在合并子树更新状态的时候,只需要考虑根与这棵子树的连边对最终答案的贡献即可,因为边的贡献只与两边点的数目有关。
注意更新状态时要像背包一样倒着更新。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 int inline readint(){ 7 int Num;char ch; 8 while((ch=getchar())<'0'||ch>'9');Num=ch-'0'; 9 while((ch=getchar())>='0'&&ch<='9') Num=Num*10+ch-'0'; 10 return Num; 11 } 12 int N,K; 13 int to[4010],ne[4010],fir[2010],cnt=0; 14 ll w[4010]; 15 void Add(int a,int b,int c){ 16 to[++cnt]=b; 17 w[cnt]=c; 18 ne[cnt]=fir[a]; 19 fir[a]=cnt; 20 } 21 int siz[2010]; 22 ll f[2010][2010]; 23 void Dfs(int x,int fa){ 24 siz[x]=1; 25 f[x][0]=f[x][1]=0; 26 for(int i=fir[x];i!=-1;i=ne[i]){ 27 int v=to[i]; 28 if(v==fa) continue; 29 Dfs(v,x); 30 for(int j=siz[x];j>=0;j--) 31 for(int k=siz[v];k>=0;k--) 32 f[x][j+k]=max(f[x][j+k],f[x][j]+f[v][k]+w[i]*(K-k)*k+w[i]*(N-siz[v]-K+k)*(siz[v]-k)); 33 siz[x]+=siz[v]; 34 } 35 } 36 int main(){ 37 N=readint(); 38 K=readint(); 39 memset(fir,-1,sizeof(fir)); 40 for(int i=1;i<N;i++){ 41 int a=readint(), 42 b=readint(), 43 c=readint(); 44 Add(a,b,c); 45 Add(b,a,c); 46 } 47 Dfs(1,0); 48 printf("%lld\n",f[1][K]); 49 return 0; 50 }