题号 NC13886
Shortest Path
西南交通大学第十三届ACM决赛
题意:
一棵偶数节点的树,分成n/2对,两两一组,所有组的路径之和最小是多少?
题解:
如果两个点之间相连将另外两个相连的点覆盖,那么完全可以改变相连方式
在这里插入图片描述
改变后路径更小,也就是说两两一组的点都不会覆盖其他点
那么每个点与其他点配对就有两者选择,一个与兄弟节点配对(中间跨过父亲点),另一个就是与父亲节点相连,这样选择肯定是最优的
如果这个节点所在的自树里有偶数个节点,那么他们内部配对就可以了(好像有什么怪怪的)
如果有奇数个节点,还有把父亲节点拉进来一起配对(这样才能组成偶数个)
来上代码:

#include<bits/stdc++.h>
using namespace std;
const int maxx=1e4+5;
typedef long long ll;
int head[maxx];
int cnt=0;
ll x,y,z;
ll ans;
struct node
{
    ll w,v,u,next;
}edge[maxx*2];
void addt(int u,int v,int w)
{
    edge[++cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].next=head[u];
    head[u]=cnt;

}
ll dfs(ll u,ll f,ll w)
{
    ll sum=1;
    for(int i=head[u];i;i=edge[i].next)
    {
        if(edge[i].v!=f)sum+=dfs(edge[i].v,u,edge[i].w);
    }
    if(sum%2)ans+=w;
    return sum;
}
int main()
{
    int T;
    int n;
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        cin>>n;
        memset(head,0,sizeof(head));
        cnt=0;
        ans=0;

        for(int i=1;i<n;i++)
        {
            scanf("%lld%lld%lld",&x,&y,&z);
            addt(x,y,z);
            addt(y,x,z); 
        }
        dfs(1,0,0);
        printf("%d\n",ans);

    }
    return 0;
}
//树上dfs