[BZOJ4033][HAOI2015]树上染色 树形DP

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4033

我们考虑用$f[i][j]$记录以第$i$个节点为根的子树,把$j$个节点染成黑色对最终的答案的最大贡献。

在合并子树更新状态的时候,只需要考虑根与这棵子树的连边对最终答案的贡献即可,因为边的贡献只与两边点的数目有关。

注意更新状态时要像背包一样倒着更新。

 1 #include
 2 #include
 3 #include
 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){
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 }

 

你可能感兴趣的:([BZOJ4033][HAOI2015]树上染色 树形DP)