BZOJ4033: [HAOI2015]树上染色【DP】

题目描述:

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

题目分析:

由于无法确定每个黑点的具体深度,所以我们将贡献分在每条边上统计
f [ u ] [ i ] f[u][i] f[u][i]表示 u u u子树内选 i i i个黑点时子树中每条边的贡献的和的最大值。
转移就看边 ( u , v ) (u,v) (u,v)两边的黑点对数以及白点对数即可。

Code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 2005
#define LL long long
using namespace std;
int n,K,siz[maxn];
LL f[maxn][maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],w[maxn<<1],tot;
inline void line(int x,int y,int z){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y,w[tot]=z;}
void dfs(int u,int ff){
    siz[u]=1;
    for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=ff){
        dfs(v,u);
        for(int j=max(K-(n-siz[v]),0);j<=siz[v]&&j<=K;j++) f[v][j]+=1ll*(j*(K-j)+(siz[v]-j)*(n-siz[v]-(K-j)))*w[i];
        for(int j=siz[u];j>=0;j--)
            for(int k=siz[v];k>=0;k--)
                f[u][j+k]=max(f[u][j+k],f[u][j]+f[v][k]);
        siz[u]+=siz[v];
    }
}
int main()
{
    scanf("%d%d",&n,&K);
    for(int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),line(x,y,z),line(y,x,z);
    dfs(1,0);
    printf("%lld\n",f[1][K]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值