题意:
给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少。
Input
一个数n(1<=n<=100,000,n保证为偶数) 接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000)
Output
一个数表示答案
Input示例
6 1 2 1 1 3 1 1 4 1 3 5 1 4 6 1
Output示例
7 //配对方案为(1,2)(3,4)(5,6)
思路:
树形dp,算贡献,单独考虑其中某一条边(u,v),因为是树上的边,所以一定是桥,假设u的一共有x个点,那么v这边一共就有n-x个点。如果要使得最后的结果最大,应该让每条边都尽可能多的被算。从贡献上来考虑,每条边的能被算次数的上限就是min(x,n-x),根据这个思路然后树形dp一波就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
struct node {
int v, w;
};
int n;
ll ans;
vector <node> tree[MAXN];
int dfs(int u, int pre) {
int cnt = tree[u].size(), res = 1;
for (int i = 0; i < cnt; i++) {
int v = tree[u][i].v, w = tree[u][i].w;
if (v == pre) continue;
int sonnum = dfs(v, u);
ans += (ll)min(sonnum, n - sonnum) * w;
res += sonnum;
}
return res;
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
tree[u].push_back((node) {v, w});
tree[v].push_back((node) {u, w});
}
ans = 0;
dfs(1, -1);
printf("%I64d\n", ans);
return 0;
}