Shortest Path

思路:

由题意可知是一个树形结构。若要使两两之间边权最小,尽量不能选重边,也就是说尽可能在节点所在子树里寻找答案。显然与叶子节点相连的边必须选。
假设当前结点为x,如果tot[x]&1==1也就是x的子树的结点数(包括x自己)为奇数时,x和父亲的边就一定要选,即答案加上edge[x].w----表示为x与父亲组成的边,当然如果它的兄弟和父亲也连了就刚好两个兄弟组成一个点对,它们的边长为他们分别与父亲的边的和。
如果tot[x]&1==0也就是x的子树的结点数(包括x自己)为偶数时,那么肯定在子树里面就互相连完了,它不需要向上连父结点。

代码

#include <bits/stdc++.h>
#define ll long long
#define  js  ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
struct tree{
    int t,w,next;
}edge[20005];
int t,n,cnt;
int head[10005],tot[10005];
ll ans;
void add(int u,int v,int len) {
    edge[++cnt].t=v;
    edge[cnt].w=len;
    edge[cnt].next=head[u];
    head[u]=cnt;
}//构造一棵无向树
void dfs(int u,int fa,int len) {
    tot[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next) { //遍历儿子结点,因为是无向的,
        int v=edge[i].t;                      //所以父结点和儿子结点会因为遍历的起点不同而不同.
        if(v==fa)    continue;    //已经遍历到叶子结点了
        dfs(v,u,edge[i].w);    //edge[i].w为它与父亲组成的边
        tot[u]+=tot[v];        //tot[x]表示包括结点x共有几个点 
    }
    if(tot[u]&1)    ans+=len; 
}
int main() {
    js;
    cin>>t;
    while(t--) {
        ans=cnt=0;
        cin>>n;
        memset(head,-1,sizeof head);
        for(int i=2;i<=n;++i) {
            int u,v,w;
            cin>>u>>v>>w;
            add(u,v,w);
            add(v,u,w);
        }
        dfs(1,0,0);
        cout<<ans<<endl;
    }
}