bzoj4033

4033: [HAOI2015]树上染色

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 1598  Solved: 667
[Submit][Status][Discuss]

Description

有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并
将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。
问收益最大值是多少。
 

Input

第一行两个整数N,K。
接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。
输入保证所有点之间是联通的。
N<=2000,0<=K<=N
 

Output

输出一个正整数,表示收益的最大值。
 

Sample Input

5 2
1 2 3
1 5 1
2 3 1
2 4 2

Sample Output

17
【样例解释】
将点1,2染黑就能获得最大收益。

HINT

 

 

 

 

Source

这道题搞了很长时间(弱爆了)
设计dp状态的时候有一个很烦人的问题,就是怎么考虑树外的点的贡献。(贡献自己脑补是什么)
碰见这种题目,我们应该这么想:既然算不了树外的,那么我们把树内能算的东西都算了。
原始思想:dp(i,j)以i为根子树内的答案的最大值,但是一旦我们想转移就gg了,于是我们把子树内的点的贡献也算上。
怎么算呢?程序里写了,w是i的父亲到i的权值,我们把子树里所有点经过这条边的贡献算上就行了。
temp每次都要清空,因为每次计算一个新的子树,答案要清空 temp保存当前这颗子树选了j个黑点的自己的最大贡献,最后再加上向外面的贡献
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2010;
struct edge {
    int nxt, to, w;
} e[N << 1];
int n, m, cnt = 1;
int head[N],  size[N];
ll dp[N][N], temp[N];
void link(int u, int v, int w)
{
    e[++cnt].nxt = head[u];
    head[u] = cnt;
    e[cnt].to = v;
    e[cnt].w = w;
}
void dfs(int u, int last, int w)
{
    size[u] = 1;
    memset(temp, 0, sizeof(temp));
    for(int i = head[u]; i ; i = e[i].nxt) if(e[i].to != last)
    {
        dfs(e[i].to, u, e[i].w);
        for(int j = 0; j <= size[u]; ++j) temp[j] = dp[u][j];
        for(int j = 0; j <= min(size[e[i].to], m); ++j)
            for(int k = 0; k <= min(size[u], m); ++k)
                temp[j + k] = max(temp[j + k], dp[u][k] + dp[e[i].to][j]);            
        size[u] += size[e[i].to];
        for(int j = 0; j <= size[u]; ++j) dp[u][j] = max(temp[j], dp[u][j]);
    }        
    for(int j = 0; j <= min(size[u], m); ++j) 
        dp[u][j] = temp[j] + ((ll)j*(ll)(m-j)+(ll)(size[u]-j)*(ll)(n-m-size[u]+j))*(ll)w;        
}
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i < n; ++i)
    {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        link(u, v, w); link(v, u, w);
    }
    dfs(1, 0, 0);
    printf("%lld\n", dp[1][m]);
    return 0;
}
View Code

 

posted @ 2017-03-18 10:33  19992147  阅读(228)  评论(0编辑  收藏  举报