有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并
将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。
问收益最大值是多少。
#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; }
原文:http://www.cnblogs.com/19992147orz/p/6571945.html