4033: [HAOI2015]树上染色
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1462 Solved: 607
[ 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
1 2 3
1 5 1
2 3 1
2 4 2
Sample Output
17
【样例解释】
将点1,2染黑就能获得最大收益。
【样例解释】
将点1,2染黑就能获得最大收益。
HINT
Source
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 2020;
typedef long long LL;
struct E{
int to,w; E(){}
E(int to,int w): to(to),w(w){}
};
LL f[maxn][maxn],g[maxn];
int n,k,siz[maxn];
vector <E> v[maxn];
void Dfs(int x,int fa)
{
siz[x] = 1;
for (int i = 0; i < v[x].size(); i++)
{
E e = v[x][i];
if (e.to == fa) continue;
Dfs(e.to,x);
for (int A = 0; A <= siz[x]; A++)
for (int B = 0; B <= siz[e.to]; B++)
{
if (A + B > k) break;
LL G = f[x][A] + f[e.to][B];
G += 1LL * e.w * B * (k - B);
G += 1LL * e.w * (siz[e.to] - B) * (n - k - siz[e.to] + B);
g[A + B] = max(g[A + B],G);
}
siz[x] += siz[e.to];
memcpy(f[x],g,sizeof(g)); memset(g,0,sizeof(g));
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> k;
for (int i = 1; i < n; i++)
{
int x,y,w; scanf("%d%d%d",&x,&y,&w);
v[x].push_back(E(y,w));
v[y].push_back(E(x,w));
}
Dfs(1,0); cout << f[1][k] << endl;
/*for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
printf("%lld ",f[i][j]);
puts("");
}*/
return 0;
}