【题解】 bzoj4033: [HAOI2015]树上染色* (动态规划)

bzoj4033,懒得复制,戳我戳我

Solution:

  • 定义状态\(dp[i][j]\)表示\(i\)号节点为根节点的子树里面有\(j\)个黑色节点时最大的贡献值
  • 然后我们要知道的就是子节点到根节点这条边会计算次数就是:子树中白色节点数\(*\)子树外白色节点数\(+\)子树中黑色节点数\(*\)子树外黑色节点数

\[dp[u][j+k]=max(dp[u][j+k], \]

\[dp[u][j]+dp[v][k]+(1ll)*k*(m-k)*dis[v]+(1ll)*(siz[v]-k)*(n-m-siz[v]+k)*dis[v]) \]

Attention:

  • 树上背包dp注意操作:
  • 这样可以保证时间复杂度是\(O(n^2)\),每次会保证是从已经获得的dp值推向未知的,就不会有多余的操作,所以我们每次枚举要添加的节点数目,加到已经求出前面几棵子树节点数目中
for(int j=min(m,siz[u]);j>=0;j--){
      int box=min(m,siz[v]);
      for(int k=box;k>=0;k--){
         dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]+1ll*k*(m-k)*dis[v]+1ll*(siz[v]-k)*(n-m-siz[v]+k)*dis[v]);
      }
    }siz[u]+=siz[v];

Code:

//It is coded by Ning_Mew on 4.24
#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int maxn=2000+7;

int n,m,fa[maxn];
LL dp[maxn][maxn];
int siz[maxn],dis[maxn];
int head[maxn],cnt=0;
struct Edge{int nxt,to,dis;}edge[maxn*2];

void add(int from,int to,int dis){
  edge[++cnt].nxt=head[from];
  edge[cnt].to=to;
  edge[cnt].dis=dis;
  head[from]=cnt;
}

void dfs(int u){
  siz[u]=1;//dp[u][0]=dp[u][1]=0;
  for(int i=head[u];i!=0;i=edge[i].nxt){
    int v=edge[i].to; if(v==fa[u])continue;
    dis[v]=edge[i].dis; fa[v]=u;
    dfs(v); //siz[u]+=siz[v];
    for(int j=min(m,siz[u]);j>=0;j--){
      int box=min(m,siz[v]);
      for(int k=box;k>=0;k--){
	dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]+1ll*k*(m-k)*dis[v]
		     +1ll*(siz[v]-k)*(n-m-siz[v]+k)*dis[v]);
      }
    }siz[u]+=siz[v];
  }return;
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n-1;i++){
    int u,v,diss;scanf("%d%d%d",&u,&v,&diss);
    add(u,v,diss);add(v,u,diss);
  }
  dfs(1);
  printf("%lld\n",dp[1][m]);
  return 0;
}

posted @ 2018-04-29 15:15  Ning_Mew  阅读(190)  评论(0编辑  收藏  举报