2020寒假【gmoj2418】【Wormhole Sort】【并查集】

题目描述

Farmer John 的奶牛们已经厌倦了他对她们每天早上排好序离开牛棚的要求。她们刚刚完成了量子物理学的博士学位,准备将这一过程搞快点。
今天早上,如同往常一样,Farmer John 的 N 头编号为 1…N 的奶牛(1≤N≤105),分散在牛棚中 N 个编号为 1…N 的不同位置,奶牛 i 位于位置 pi。但是今天早上还出现了 M 个编号为 1…M 的虫洞(1≤M≤105),其中虫洞 i 双向连接了位置 ai 和 bi,宽度为 ( 1 ≤ a i , b i ≤ N , a i ≠ b i , 1 ≤ w i ≤ 1 0 9 ) (1≤ai,bi≤N,ai≠bi,1≤wi≤10^9) (1ai,biN,ai=bi,1wi109
在任何时刻,两头位于一个虫洞两端的奶牛可以选择通过虫洞交换位置。奶牛们需要反复进行这样的交换,直到对于 1≤i≤N,奶牛 i 位于位置 i。
奶牛们不想被虫洞挤坏。帮助她们最大化被她们用来排序的虫洞宽度的最小值。保证奶牛们有可能排好序。

输入

输入的第一行包含两个整数 N 和 M。
第二行包含 N 个整数 p1,p2,…,pN。保证 p 是 1…N 的一个排列。
对于 1 到 M 之间的每一个 i,第 i+2 行包含整数 ai、bi 和 wi。

输出

输出一个整数,为在排序过程中奶牛必须挤进的虫洞的最小宽度的最大值。如果奶牛们不需要用任何虫洞来排序,输出 −1。

样例输入

4 4
3 2 1 4
1 2 9
1 3 7
2 3 10
2 4 3

样例输出

9

数据范围限制

测试点 1-5 满足 N,M≤1000。
测试点 6-10 没有额外限制。

提示

​以下是一个仅用宽度至少为 9 的虫洞给奶牛排序的可能方案:
奶牛 1 和奶牛 2 使用第三个虫洞交换位置。
奶牛 1 和奶牛 3 使用第一个虫洞交换位置。
奶牛 2 和奶牛 3 使用第三个虫洞交换位置。

分析

题意就是说有n 个虫洞,在两个地方传送,现在问你让所有的奶牛都到自己的地方所穿过的虫洞宽度最小的最大值是多少。
抓住关键信息:
1.一个虫洞如果确定了要经过,那么就可以无限经过这个虫洞。
2.当确定一个虫洞要经过之后,宽度比他大的虫洞都可以经过。
本题要用到并查集和一点小小的贪心,每次加入一条最大的边,然后看看是否连通即可,因为本题数据范围较小,所以不需要启发式合并,具体做法详见代码注释。

上代码

#include
#include
#include
using namespace std;
int n,m,a[100001],fx,fy,f[100001];
struct node
{
	int x,y,z;//x,y节点,z宽度 
}b[100001]; 
int cmp(node l,node r)
{
	return l.z>r.z;
}
int father(int k)//并查集“找爸爸”不多说 
{
	if(f[k]==k) return k;
	return f[k]=father(f[k]);
}
int main()
{
	freopen("wormsort.in","r",stdin);
	freopen("wormsort.out","w",stdout);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
	}
	for(int i=1;i<=m;i++)
	{
		cin>>b[i].x>>b[i].y>>b[i].z;
	}
	sort(b+1,b+m+1,cmp);
	int s=0,ans=-1;
	for(int i=1;i<=n;i++)
	{
		f[i]=i;//初始化,每个节点最初的"根"是自己 
	}
	for(int i=1;i<=m;i++)
	{
		while(father(s)==father(a[s]))//判断连通性
		{
			s++;
			if(s>=n-1)
			{
				cout<<ans;
				return 0;
			} 
		} 
		fx=father(b[i].x);
		fy=father(b[i].y);
		if(fx!=fy)//不连通 
		{
			f[fx]=fy;//加边 
			ans=b[i].z;
		}
	}
	cout<<ans;
	fclose(stdin);
	fclose(stdout);
    return 0;
}

你可能感兴趣的:(并查集,纪中集训,图论)