构造完全图(G)解题报告

题目描述

对于完全图 G,若有且仅有一棵最小生成树为 T,则称完全图 G 是树 T 扩展出的。

给你一棵树 T,找出 T 能扩展出的边权和最小的完全图 G。

输入格式

第一行 N 表示树 T 的点数;

接下来 N−1 行三个整数 Si,Ti,Dii​​,Ti​​,Di​​;描述一条边(Si,TiS_i, T_iSi​​,Ti​​)权值为 DiD_iDi​​;

保证输入数据构成一棵树。

输出格式

输出仅一个数,表示最小的完全图 G 的边权和。

样例

样例输入

4  
1 2 1  
1 3 1  
1 4 2

样例输出

12

样例说明

添加 D(2,3)=2,D(3,4)=3,D(2,4)=3D(2, 3)=2, D(3, 4)=3, D(2, 4)=3D(2,3)=2,D(3,4)=3,D(2,4)=3 即可。

题目链接:https://loj.ac/problem/10067

解题思路:首先完全图是指每两个点之间都有连边的图,题目是要求一个边权和最小的完全图,

题目给出的是一个最小生成树,我们可以从边入手,把每条边所连的左右两个点分别看做一个集合,

左边集合和右边集合所要连的边数是(cnt[i]*cnt[j]-1),我们要连的边权是多大?不能比当前的边还小,

那么就不满足有且仅有一棵最小生成树T,所以边权就为(当前边的边权+1),我们可以贪心的去解决,

把边从小到大排序,并查集一下就行了,当然还得加上原始边的边权。

 

代码如下:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long int
using namespace std;
struct T{
    ll u,v,w;
}t[100005];
ll ans,n,cnt[100005],fa[100005];
ll find(ll x){
    if(fa[x]!=x)
    return fa[x]=find(fa[x]);
    else
    return fa[x];
}
bool cmp(T a,T b){return a.w<b.w;}
int main(){
    scanf("%lld",&n);
    for(ll i=1;i<=n-1;i++)
    scanf("%lld%lld%lld",&t[i].u,&t[i].v,&t[i].w),ans+=t[i].w;
    for(ll i=1;i<=n;i++){
        fa[i]=i;cnt[i]=1;
    }
    sort(t+1,t+n,cmp);
    for(ll i=1;i<=n-1;i++){
        ll r1=find(t[i].u);
        ll r2=find(t[i].v);
        if(r1!=r2){
            ans+=(cnt[r1]*cnt[r2]-1)*(t[i].w+1);
            fa[r2]=r1;
            cnt[r1]+=cnt[r2];
        }
    }
    printf("%lld",ans);
    return 0;
}

 

 

 

posted @ 2018-09-06 14:55  zxza695  阅读(1766)  评论(0编辑  收藏  举报

Contact with me