cogs 1962. [HAOI2015]树上染色

                ★★☆   输入文件:haoi2015_t1.in   输出文件:haoi2015_t1.out   简单对比
                    时间限制:1 s   内存限制:256 MB

【题目描述】

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

【输入格式】

第一行两个整数N,K。

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

【输出格式】

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

【输入样例1】

3 1

1 2 1

1 3 2

【输出样例1】

3

【输入样例2】

5 2

1 2 3

1 5 1

2 3 1

2 4 2

【输出样例2】

17

【样例解释】

在第二个样例中,将点1,2染黑就能获得最大收益。

【数据范围】

对于30%的数据,N<=20

对于50%的数据,N<=100

对于100%的数据,N<=2000,0<=K<=N

 

题解:

  这是一道树形DP,考虑对于每一条边,它对答案的贡献值=两端的黑点个数乘积*边权+两端白点个数乘积*边权。

  令f[i][j]表示以i为根的子树中,有j个黑点的最大收益。对于某一个节点x及其某一儿子y,考虑x与y的连边对答案的贡献,我们可以先枚举x中的黑点个数,再枚举y的黑点个数,用类似01背包来转移。

 1 /**************************************************************
 2     Problem: 4033
 3     User: __abcdef__
 4     Language: C++
 5     Result: Accepted
 6     Time:6824 ms
 7     Memory:32932 kb
 8 ****************************************************************/
 9  
10 #include<iostream>
11 #include<cstdio>
12 #include<cstdlib>
13 #include<cstring>
14 #include<cmath>
15 #include<algorithm>
16 #include<queue>
17 #include<vector>
18 using namespace std;
19 typedef long long LL;
20 const LL inf=1e15,maxn=2010;
21 LL N,K;
22 vector<LL> to[maxn],cost[maxn];
23 LL fa[maxn],f[maxn][maxn],siz[maxn];
24 inline void dfs(LL x,LL fath){
25     fa[x]=fath; siz[x]=1;
26     for(int i=0;i<to[x].size();i++){
27         LL y=to[x][i];
28         if(y!=fath){
29             dfs(y,x);
30             siz[x]+=siz[y];
31         }
32     }
33 }
34  
35 inline void calc(LL x){//计算以x为根的情况 
36     f[x][0]=0; f[x][1]=0;
37     if(siz[x]==1) return ;//叶子节点
38     for(int i=0;i<to[x].size();i++){//枚举子树 
39         LL y=to[x][i],val=cost[x][i]; 
40         if(y!=fa[x]){
41             calc(y);
42             for(int tot=min(K,siz[x]);tot>=0;tot--){//枚举以x为根的子树中有几个黑点  
43                 for(int j=0;j<=min(siz[y],K)&&j<=tot;j++){//这个子树中有多少黑点 
44                     LL ans1=(LL)j*(K-(LL)j)*val;
45                     LL ans2=(siz[y]-(LL)j)*(N-K-(siz[y]-(LL)j))*val;
46                     LL tmp=f[y][j]+ans1+ans2;
47                     f[x][tot]=max(f[x][tot],f[x][tot-j]+tmp);   
48                 }
49             }
50         }
51     }
52 }
53  
54 int main(){
55     scanf("%lld%lld",&N,&K);
56     for(int i=1;i<=N-1;i++){
57         LL u,v,c;
58         scanf("%lld%lld%lld",&u,&v,&c);
59         to[u].push_back(v); cost[u].push_back(c);
60         to[v].push_back(u); cost[v].push_back(c);
61     }
62     for(int i=1;i<=N;i++){
63         for(int j=1;j<=N;j++){
64             f[i][j]=-inf;
65         }
66     }
67     dfs(1,-1);
68     calc(1);
69     printf("%lld\n",f[1][K]);
70     return 0;
71 }

 

posted @ 2016-04-16 22:46  CXCXCXC  阅读(951)  评论(0编辑  收藏  举报