https://ac.nowcoder.com/acm/problem/13886
题意:
给一棵树,保证树的结点个数是偶数,定义点对的价值是他们的距离,求将这棵树分成 n/2 个点对之后,这些点对的最小价值。
解法:
贪心的考虑,我们希望使得一颗树内的点两两组合,这样代价会最小,如果这棵树的结点个数是偶数个的话,我们将他在树内的所有结点两两结合。否则,为了代价最小,我们选择子树的根节点向子树外连边,其他的偶数个结点连边,这样代价会最小。
所以答案就是所有奇数个数节点的子树的根节点到他爸爸的距离。就和树剖的dfs1一样,先求出子树的大小,然后判断是否是奇数即可一次dfs解决。
#include <bits/stdc++.h> #define ll long long #define sc scanf #define pr printf using namespace std; const int MAXN = 1e4 + 5; struct edge { int to; ll w; int nex; }e[MAXN * 2]; int head[MAXN], tot; void init() { memset(head, -1, sizeof(head)); tot = 1; } void add(int a, int b, ll c) { e[tot] = edge{ b,c,head[a] }; head[a] = tot++; } int sz[MAXN]; ll ans; void dfs(int u, int f) { sz[u] = 1; for (int i = head[u]; i + 1; i = e[i].nex) { int to = e[i].to; if (to == f) continue; dfs(to, u); sz[u] += sz[to]; if (sz[to] & 1) ans += e[i].w; } } int main() { int T; sc("%d", &T); while (T--) { ans = 0; init(); int n; sc("%d", &n); for (int i = 1; i < n; i++) { int a, b; ll c; sc("%d%d%lld", &a, &b, &c); add(a, b, c); add(b, a, c); } dfs(1, 0); pr("%lld\n", ans); } }