zoukankan      html  css  js  c++  java
  • 构造完全图(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;
    }
  • 相关阅读:
    学习日报
    阅读笔记2
    学习日报
    记账本开发7
    记账本开发6
    学习日报
    记账本开发5
    今日总结
    今日总结
    家庭记账本7
  • 原文地址:https://www.cnblogs.com/sky-zxz/p/9598331.html
Copyright © 2011-2022 走看看