题意:给出一棵有偶数的节点的树,将其分成n/2对点,并且要求n/2对点的路径之和最小
涉及知识点:思维/树上dfs
思路:树上任意两点间的距离是唯一的,题目又要求路径之和最小,所以选择两个节点,要么是父节点和其孩子节点,要么是父节点的两个孩子节点,还有一种情况是多了一个孩子节点,那么肯定要先加上到父节点的距离,然后再和另外一个节点配对。
所以在树上dfs,枚举子树的节点个数,一颗子树如果节点个数为偶数,就不需要再添加节点配对,如果节点个数为奇数,需要和父节点往外的一个节点配对,那么答案就要加上这颗子树到父节点的距离代码:
#include <bits/stdc++.h> using namespace std; #define ll long long const int maxn = 10005; struct node{ int t,nex; ll w; }; node a[maxn<<1]; int head[maxn],tot,cnt[maxn]; ll ans ; void add(int x,int y,ll z){ a[++tot].t = y,a[tot].nex = head[x],a[tot].w = z,head[x] = tot; } void dfs(int x,int fath,ll w) { cnt[x] = 1; for(int i=head[x] ; i ; i = a[i].nex){ if(a[i].t != fath){ dfs(a[i].t , x , a[i].w); cnt[x] += cnt[a[i].t]; } } if(cnt[x]%2) ans += w; } int main() { int t; cin>>t; while(t--) { tot = 0,ans = 0; int n,x,y; scanf("%d",&n); memset(cnt, 0 ,sizeof(cnt)); memset(head , 0,sizeof(head)); for(int i=1;i<n;i++){ ll z; cin>>x>>y>>z; add(x, y, z),add(y, x, z); } dfs(1 , 0 , 0); cout<<ans<<endl; } return 0; }
```