首页 > 其他 > 详细

[HAOI2015]树上染色(树形dp)

时间:2019-11-12 22:26:00      阅读:82      评论:0      收藏:0      [点我收藏+]

传送门

这道题还是打一下,毕竟也是一道比较经典的题。

思想值得学习:求点两两之间的距离和不如转化成看一条边会对哪些点对做出贡献。

下面以黑点为例,白点同理。

那么对于一条边(x,y)

根据乘法原理:它对黑点距离的贡献即为y子树内的黑点点数 * y子树外的黑点点数。

于是我们就要对点分配哪些点为黑点,转化为树上背包问题。

然后有一点值得注意,在代码内有注释。

技术分享图片
#include<bits/stdc++.h>
#define LL long long 
#define N 2003
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<0||s>9){if(s==-)f=-1;s=getchar();}
    while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
    return x*f;
}
void print(int x)
{
    if(x<0)x=-x,putchar(-);
    if(x>9)print(x/10);
    putchar(x%10+0);
}
struct EDGE{
    int nextt,to,dis;
}w[N*2];
int n,K;
int tot=0;
int head[N],siz[N];
LL f[N][N];
void add(int a,int b,int c)
{
    tot++;
    w[tot].nextt=head[a];
    w[tot].to=b;
    w[tot].dis=c;
    head[a]=tot;
}
void dfs(int x,int fa)
{
    siz[x]=1;f[x][0]=f[x][1]=0;
    for(int i=head[x];i;i=w[i].nextt)
    {
        int v=w[i].to;
        if(v==fa)continue;
        dfs(v,x);
        siz[x]+=siz[v];
        for(int j=min(K,siz[x]);j>=0;--j)
        {
            if(f[x][j]!=-1)
              f[x][j]+=f[v][0]+(LL)siz[v]*(n-K-siz[v])*w[i].dis;
            //正序转移和倒序转移在本质上并没有差别,但是在这道题中,对于当前枚举的子节点的子树,哪怕一个黑点也没有,
            //它仍然可以对答案产生贡献,所以我们要先算上这种情况的贡献,否则在接下来的转移中,就会少计算本来就有的价值
            for(int k=min(j,siz[v]);k;--k)
            {
                if(f[x][j-k]==-1)continue;
                LL val=(LL)(k*(K-k)+(siz[v]-k)*(n-K-siz[v]+k))*w[i].dis;
                f[x][j]=max(f[x][j],f[x][j-k]+f[v][k]+val);
            }
        }
    }
}
int main()
{
    n=read();K=read();
    for(int i=1;i<n;++i)
    {
        int a=read(),b=read(),c=read();
        add(a,b,c);add(b,a,c);
    }
    memset(f,-1,sizeof(f));
    dfs(1,1);
    printf("%lld\n",f[1][K]);
}
/*
*/
View Code

[HAOI2015]树上染色(树形dp)

原文:https://www.cnblogs.com/yyys-/p/11844833.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!