HAOI2015 树上染色

传送门

非常神奇的树形DP……

可能和大多数人一样吧,一开始我令dp[i][j]表示以i为根的子树选择j个黑点的最大价值,之后就不会转移了……

后来发现这个状态设的并不对,因为我们要考虑的是对答案的总贡献,而不是每个子树内的价值,也就是我们要考虑的是每条边对答案的贡献。

这个式子很显然的,但是像我这样是肯定考虑不到的……

于是就把这个问题转化成了树上背包,我们把在子树内选取的黑点看作体积,贡献看作价值,之后我们进行DP即可。注意这道题的关键是,对于答案的贡献并不只局限于子树内,而是对于整棵树而言。

令dp[i][j]表示以i为根的子树选择j个黑点的最大贡献,那么dp[i][j] = max(dp[i][j],dp[i][t] + dp[v][j-t] + val),val是计算的贡献。

这样进行DP就可以啦。

看一下代码。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 2005;
const int INF = 1000000009;

ll read()
{
    ll ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

struct edge
{
    int next,to;
    ll v;
}e[M<<1];

ll dp[M][M],ans,x,y,z,ecnt,head[M];
int size[M],n,k;

void add(int x,int y,int z)
{
    e[++ecnt].to = y;
    e[ecnt].next = head[x];
    e[ecnt].v = z;
    head[x] = ecnt;
}

void dfs(int x,int fa)
{
    size[x] = 1,dp[x][0] = dp[x][1] = 0;
    for(int i = head[x];i;i = e[i].next)
    {
    if(e[i].to == fa) continue;
    dfs(e[i].to,x);
    size[x] += size[e[i].to];
    }
    for(int i = head[x];i;i = e[i].next)
    {
    int v = e[i].to;
    if(v == fa) continue;
    per(j,min(k,size[x]),0)
        rep(p,0,min(j,size[v]))
    {
        if(dp[x][j-p] != -1)
        {
        ll val = (ll)(e[i].v * p * (k-p)) + (ll)(e[i].v * (size[v] - p) * (n-k+p-size[v]));
        dp[x][j] = max(dp[x][j],dp[v][p] + dp[x][j-p] + val);
        }
    }    
    }
}

int main()
{
    n = read(),k = read();
    memset(dp,-1,sizeof(dp));
    rep(i,1,n-1) x = read(),y = read(),z = read(),add(x,y,z),add(y,x,z);
    dfs(1,0);
    printf("%lld\n",dp[1][k]);
    return 0;
}

 

posted @ 2018-10-21 00:06  CaptainLi  阅读(148)  评论(0编辑  收藏  举报