7.15模拟赛

T2.coloration

树形DP,提供了一种好的思路。

涉及考虑树上点对的题,与其O(n^2)地考虑任意两点的关系,不如考虑每条边的贡献。

本题中,对于一条边e,它的边权为w,其贡献为 (左侧黑点*右侧黑点+左侧白点*右侧白点)*w

设f[i][j]为以i为根的子树中选取j个黑点的最大贡献,转移时逐个合并子树,用一个g数组先跑一次背包,再添加进f状态。

复杂度O(n^2),卡好边界。

注意int到long long要乘一个1ll

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

const int MAXN=2048;

inline int rd() {
    int ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

struct Edge {
    int next,to,w;
} e[MAXN<<1];
int ecnt,head[MAXN];
inline void add(int x,int y,int w) {
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].w = w;
    head[x] = ecnt;
}

int n,m;
long long f[MAXN][MAXN],g[MAXN];
int siz[MAXN];
int dfs(int x,int pre) {
    siz[x]=1;
    for(int i=head[x]; i; i=e[i].next) {
        int v=e[i].to;
        if(v==pre) continue;
        memset(g,0,sizeof(g));
        dfs(v,x);
        for(int j=min(m,siz[x]); j>=0; j--)
            for(int k=min(m-j,siz[v]); k>=0; k--)
                g[j+k]=max(g[j+k],
                f[x][j]+f[v][k]+((k*(m-k)+(siz[v]-k)*(n-m-siz[v]+k))*1ll*e[i].w));
        for(int j=0; j<=m; j++)f[x][j]=g[j];
        siz[x]+=siz[v];
    }
}


int main() {
    n=rd();
    m=rd();
    int x,y,w;
    for(int i=1; i<=n-1; i++) {
        x=rd();y=rd();w=rd();
        add(x,y,w);add(y,x,w);
    }
    dfs(1,0);
    cout<<f[1][m];
}
View Code

猜你喜欢

转载自www.cnblogs.com/ghostcai/p/9314178.html