★★☆ 输入文件: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 ",f[1][K]); 70 return 0; 71 }