版权声明: https://blog.csdn.net/moon_sky1999/article/details/81776851
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=4118
树形dp,思路来自:https://www.cnblogs.com/kiuhghcsc/p/5707140.html
题意:给定一棵树,每个节点的人需要离开此节点到另一个节点,且任意两人不能到相同的节点,求经过的路程的最大值。
思路:对于每条边<u,v>,其最多被经过的次数最多为min(f[v],f[u])。其中f[i]表示,这棵树被该边分开后一侧的所有点数。最终结果即为所有边累加后的结果。
代码:
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int n, head[maxn], cnt, f[maxn];
struct edge {
int to, next, vi;
} e[maxn * 2];
void ins(int x, int y, int z) {
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].vi = z;
head[x] = cnt;
}
int dfs(int root, int fa) {
f[root] = 1;
for (int i = head[root]; i; i = e[i].next) {
if (e[i].to != fa) {
f[root] += dfs(e[i].to, root);
}
}
return f[root];
}
int main() {
int _;
scanf("%d", &_);
for (int sce = 1; sce <= _; ++sce) {
cnt = 0;
memset(head, 0, sizeof(head));
scanf("%d", &n);
int x, y, z;
for (int i = 1; i < n; ++i) {
scanf("%d%d%d", &x, &y, &z);
ins(x, y, z);
ins(y, x, z);
}
dfs(1, 0);
ll ans = 0;
for (int i = 1; i <= n; ++i) {
for (int j = head[i]; j; j = e[j].next) {
ll t = min(f[i], f[e[j].to]);
t = min(t, n - t);
ans += t * e[j].vi;
}
}
printf("Case #%d: %lld\n", sce, ans);
}
return 0;
}