• BZOJ_4033_[HAOI2015]树上染色_树形DP


    BZOJ_4033_[HAOI2015]树上染色_树形DP

    Description

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

    Input

    第一行两个整数N,K。
    接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。
    输入保证所有点之间是联通的。
    N<=2000,0<=K<=N

    Output

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

    Sample Input

    5 2
    1 2 3
    1 5 1
    2 3 1
    2 4 2

    Sample Output

    17
    【样例解释】
    将点1,2染黑就能获得最大收益。

    HINT

    2017.9.12新加数据一组 By GXZlegend


    树形背包,设f[i][j]表示i子树里选了j个黑点的最大收益。

    转移时考虑父亲到儿子的这条边两端分别有多少个黑-黑  白-白统计一下贡献即可。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    using namespace std;
    typedef long long ll;
    #define N 2050
    int K,head[N],to[N<<1],nxt[N<<1],val[N<<1],cnt,n;
    int siz[N];
    ll f[N][N];
    inline void add(int u,int v,int w) {
    	to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
    }
    void dfs(int x,int y) {
    	int i,j,k,flg=1; siz[x]=1;
    	for(i=head[x];i;i=nxt[i]) {
    		if(to[i]!=y) {
    			flg=0;
    			dfs(to[i],x);
    			for(j=siz[x];j>=0;j--) {
    				for(k=siz[to[i]];k>=0;k--) {
    					f[x][j+k]=max(f[x][j+k],f[x][j]+f[to[i]][k]+val[i]*(ll(k)*(K-k)+ll(siz[to[i]]-k)*(n-K-siz[to[i]]+k)));
    				}
    			}
    			siz[x]+=siz[to[i]];
    		}
    	}
    	if(flg) f[x][0]=f[x][1]=0;
    }
    int main() {
    	// memset(f,0x80,sizeof(f));
    	scanf("%d%d",&n,&K);
    	int i,x,y,z;
    	for(i=1;i<n;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
    	dfs(1,0);
    	printf("%lld
    ",f[1][K]);
    }
    
  • 相关阅读:
    Linux中的Diff和Patch
    旧磁带,新风险
    Mac下体验Hexo与Github Pages搭建
    Sublime Text 3 提高工作效率的使用技巧
    PHPExcel对于Excel中日期和时间类型的处理
    做Adsense的一些经验
    使用Fusioncharts实现后台处理进度的前台展示
    iOS: 数据持久化方案
    开发中,理解高内聚、低耦合
    iOS: lame框架将PCM录音转成MP3格式
  • 原文地址:https://www.cnblogs.com/suika/p/9464301.html
Copyright © 2020-2023  润新知