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);
}
} 
京公网安备 11010502036488号