题目
分析
考虑 表示 子树中有 个黑点时,对答案的贡献,转移过程中计算边 的贡献即可。注意贡献有白色贡献和黑色贡献。
代码
#include <algorithm>
#include <cstdio>
#include <cstring>
typedef long long LL;
const int MAXN = 2000;
int N, K;
struct Node {
int v, w, nxt;
}E[MAXN * 2 + 5];
int EdgeCnt;
int Adj[MAXN + 5];
void AddEdge(int u, int v, int w) {
E[++EdgeCnt] = (Node){v, w, Adj[u]};
Adj[u] = EdgeCnt;
}
int Size[MAXN + 5];
LL Dp[MAXN + 5][MAXN + 5];
void Dfs(int u, int fa) {
Size[u] = 1;
for (int i = Adj[u]; i; i = E[i].nxt) {
int v = E[i].v;
if (v != fa)
Dfs(v, u), Size[u] += Size[v];
}
Dp[u][0] = Dp[u][1] = 0;
for (int i = Adj[u]; i; i = E[i].nxt) {
int v = E[i].v; LL w = E[i].w;
if (v != fa) {
for (int j = std::min(K, Size[u]); j >= 0; j--) {
int lim = std::min(Size[v], j);
for (int k = 0; k <= lim; k++) {
if (~Dp[u][j - k]) {
LL p = Size[v] - k;
LL delta = w * (k * (K - k) + p * (N - K - p));
Dp[u][j] = std::max(Dp[u][j], Dp[u][j - k] + Dp[v][k] + delta);
}
}
}
}
}
}
int main() {
scanf("%d%d", &N, &K);
for (int i = 1; i < N; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
AddEdge(u, v, w), AddEdge(v, u, w);
}
memset(Dp, -1, sizeof Dp);
Dfs(1, 0);
printf("%lld\n", Dp[1][K]);
return 0;
}