并查集的一般操作 ①

Rt

题目背景

A地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。

题目描述

给出A地区的村庄数N,和公路数M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)

输入输出格式

输入格式:

第1行两个正整数N,M

下面M行,每行3个正整数x, y, t,告诉你这条公路连着x,y两个村庄,在时间t时能修复完成这条公路。

输出格式:

如果全部公路修复完毕仍然存在两个村庄无法通车,则输出-1,否则输出最早什么时候任意两个村庄能够通车。

输入

4 4
1 2 6
1 3 4
1 4 5
4 2 3

输出

5

分析:

首先读题发现是一道并查集的  题,先对t从小到大排序,然后挨个合并,但怎么判断合并全了?

这时我们需要一个很巧妙的方法

可以建一个val[ ]=1;然后集合合并时val相加

详见代码:

#include <cstdio>
#include <algorithm>

using namespace std;

int n,m;
int val[1000010];
//并查集
struct b
{
    int par[1000100];
    inline void ih(){for(int i=1;i<=n;++i) {par[i]=i;val[i]=1;}}
    inline int f (int x){return par[x]=(par[x]==x)?x:f(par[x]);}
    inline int u (int x,int y)
    {

        val[f(x)]+=val[f(y)];//对祖先的val操作
        par[f(y)]=f(x);
    }
    inline int get_val (int x)
    {
        return val[f(x)];
    }
}s;
struct data
{
    int x,y,t;
    friend bool operator < (data a,data b)
    {
        return a.t<b.t;
    }
}a[10100000];
int sum=2,ans;
bool flag=0;
int main()
{
    freopen("in","r",stdin);
    scanf("%d%d",&n,&m);
    scanf("%d%d%d",&a[0].x,&a[0].y,&a[0].t);
    for(int i=1;i<m;++i)
    {
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
    }
    sort(a,a+m);
    s.ih();
    for(int i=0;i<m;++i)
    {
        if(s.f(a[i].x)!=s.f(a[i].y))
        {
            s.u(a[i].x,a[i].y);
            ans=a[i].t;
            if(s.get_val(a[i].x)==n)
            {
                printf("%d",ans);
                flag=1;
                break;
            }
        }
    }
    if(flag==0)
    {
        printf("-1");
    }
}
View Code
原文地址:https://www.cnblogs.com/AidenPearce/p/8277053.html