• [20200717NOIP提高组模拟T3]水管


    题目大意:

      给你$n$个点和$m$条边,要求你输出最小生成树的边权之和并判断最小生成树是否唯一.

    solution:

      最小生成树板子,Kruskal即可.至于判断唯一性,这里有一种耐人寻味的解法.对于每一个边权值$z$,我们可以寻找所有边权与其相等的边并统计其中合法边数sum,然后再扫描一次选其中足够的合法边并加入最小生成树,如果有剩余的合法边,则说明可以替换,即最小生成树不唯一.

    code:

      

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define R register
    #define next exnt
    #define debug puts("mlg")
    using namespace std;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    inline ll read();
    inline void writesp(ll x);
    inline void writeln(ll x);
    inline void write(ll x);
    ll T;
    ll n,m;
    struct node{
        ll X,Y,Z;
    }t[220000];
    inline bool cmp(node x,node y){
        return x.Z<y.Z;
    }
    ll f[220000];
    inline void init(){
        for(R ll i=1;i<=n;i++) f[i]=i;
    }
    inline ll getf(ll x){
        return f[x]==x?x:f[x]=getf(f[x]);
    }
    inline bool check(ll x,ll y){
        return getf(x)==getf(y);
    }
    inline void merge(ll x,ll y){
        f[getf(y)]=getf(x);
    }
    ll sum,total,ans;
    int main(){
        T=read();
        while(T--){
            n=read(),m=read();
            init();
            for(R ll i=1;i<=m;i++) t[i].X=read(),t[i].Y=read(),t[i].Z=read();
            sort(t+1,t+m+1,cmp);
            total=ans=sum=0;
            for(R ll i=1;i<=m;i++){
                for(R ll j=i;j<=m&&t[j].Z==t[i].Z;j++){
                    if(!check(t[j].X,t[j].Y)){
                        ++sum;
                    }
                }
                do{
                    if(!check(t[i].X,t[i].Y)){
                        merge(t[i].X,t[i].Y);
                        ans+=t[i].Z;
                        ++total;
                    }
                    if(total==n-1) break;
                    ++i;
                }while(t[i].Z==t[i-1].Z&&i<=m);
                if(total==n-1) break;
                --i;
                
            }
            writeln(ans);
            if(sum>n-1) puts("No");
            else puts("Yes");
        }
    }
    inline ll read(){
        ll x=0,t=1;char ch=getchar();
        while(ch<'0'||ch>'9'){
            if(ch=='-') t=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';
            ch=getchar();
        }
        return x*t;
    }
    inline void write(ll x){
        if(x<0){putchar('-');x=-x;}
        if(x<=9){putchar(x+'0');return;}
        write(x/10);putchar(x%10+'0');
    }
    inline void writesp(ll x){
        write(x);putchar(' ');
    }
    inline void writeln(ll x){
        write(x);putchar('
    ');
    }

    感谢机房神犇zxt提供思路

  • 相关阅读:
    10、函数介绍、函数参数、函数的返回值
    9、bytes类型,文件处理
    8、集合类型、文件处理
    7、列表类型、元组、字典类型
    6、for循环补充、可变类型与不可变类型、基本操作
    5、while循环与for循环
    4、基本运算符、if语法
    3、变量、常量、基本数据类型
    爬虫(一)
    小技能(二)
  • 原文地址:https://www.cnblogs.com/ylwtsq/p/13331397.html
Copyright © 2020-2023  润新知