【Luogu】P3177树上染色(树形DP)

  题目链接

  题没想出来很烦+一堆细节要注意很烦。

  当然更可能是我智商被osu吃了。

  考虑一条边会有什么贡献?它一边的黑点数*另一边的黑点数*边权。

  +它一边的白点数*另一边的白点数*边权。

  这样一来就成了一个树形背包

  

#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#define maxn 2030
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

struct Edge{
    long long next,to,dis;
}edge[maxn*3];
long long head[maxn],num;
inline void add(long long from,long long to,long long dis){
    edge[++num]=(Edge){head[from],to,dis};
    head[from]=num;
}

long long n,m;
long long size[maxn];
long long f[maxn][maxn];

void build(long long x,long long fa){
    size[x]=1;
    for(long long i=head[x];i;i=edge[i].next){
        long long to=edge[i].to;
        if(to==fa)    continue;
        build(to,x);
        size[x]+=size[to];
    }
}

inline long long calc(long long i,long long x){
    return (m-x)*x*edge[i].dis+(n-m+x-size[edge[i].to])*(size[edge[i].to]-x)*edge[i].dis;
}

void dfs(long long x,long long fa){
    memset(f[x],-1,sizeof(f[x]));    f[x][0]=f[x][1]=0;
    for(long long i=head[x];i;i=edge[i].next){
        long long to=edge[i].to;
        if(to==fa)    continue;
        dfs(to,x);
        for(long long j=min(m,size[x]);j>=0;--j){
            for(long long k=0;k<=min(j,size[to]);++k)
                if(f[x][j-k]!=-1)    f[x][j]=max(f[x][j],f[x][j-k]+f[to][k]+calc(i,k));
        }
    }
    return;
}

int main(){
    n=read(),m=read();
    for(long long i=1;i<n;++i){
        long long from=read(),to=read(),dis=read();
        add(from,to,dis);
        add(to,from,dis);
    }
    build(1,1);
    dfs(1,1);
    printf("%lld
",f[1][m]);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8342623.html