BZOJ 4033 [HAOI2015]树上染色

本文介绍了一种树形动态规划(树DP)算法的应用实例。通过分析每条边对答案的贡献,利用树上的背包思想来解决特定问题。文章提供了完整的代码实现,并详细解释了关键步骤,包括如何正确设置初始值及双向边等问题。

树DP 。 

考虑每条边对答案的贡献是边两边的黑点数乘积加白点数乘积乘以边长。所以我们只要知道一个点的某个子树中的黑点数就可以算它到子树这条边的贡献。

就可以树上跑背包。

注意一是不要随便只开单向边(会GG),二是DP初值设为-1,dp[x][0].dp[x][1]初始为0,这样不会考虑不存在的状态。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
typedef long long LL;
using namespace std;
const int maxn=2005;
int n,k,x,y,z,fir[maxn],nxt
[maxn*2],to[maxn*2],ecnt,sz[maxn];
LL val[maxn*2],dp[maxn][maxn];
void add(int u,int v,LL w) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v; val[ecnt]=w;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u; val[ecnt]=w;
}
void DFS(int x,int f) {
    sz[x]=1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){
        DFS(to[i],x);
        sz[x]+=sz[to[i]];
    }
}
void dfs(int x,int f) {
    memset(dp[x],-1,sizeof(dp[x])); dp[x][0]=dp[x][1]=0;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f){
        dfs(to[i],x);
        int u=to[i],up=min(k,sz[x]);
        for(int v=up;v>=0;v--) {
             for(int j=0;j<=sz[u]&&j<=v;j++) if(dp[x][v-j]!=-1){
                 dp[x][v]=max(dp[x][v],dp[x][v-j]+dp[u][j]+(LL)(j*(k-j)+(sz[u]-j)*(n-sz[u]-k+j))*val[i]);
             }
        }
    }
}
int main()
{
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++) {
        scanf("%d%d%lld",&x,&y,&z);
        add(x,y,z);
    }
    DFS(1,0);
    dfs(1,0);
    printf("%lld\n",dp[1][k]);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Achenchen/p/7524389.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值