加入边前判断两个节点是否根节点相同,如果相同那么成环,如果不同合并他们
比如1-2,1-3,2-3,加入2-3时2和3已经同属一个并查集了,成环
例题 HDU 1272
值得注意的是,这道题任意两个房间有且仅有一条路径可以相通,也就是说最后有且仅有一个并查集,不能出现多个并查集!不能仅仅判断是否成环
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=1000001;
int f[N],vis[N];
void init() { //初始化
for(int i=1; i<=N; i++) f[i]=i;
}
int find(int i) {//路径压缩
return f[i]==i ? f[i] : f[i]=find(f[i]);
}
void merge(int a,int b) {
int faA=find(a);
int faB=find(b);
if(faA==faB) return;//判断它们是否属于同一集合
else {
f[faA]=faB;//把其中一个的父亲结点指向另一个结点
}
}
int main() {
int a,b;
while(1) {
scanf("%d%d",&a,&b);
if(a==-1) break;
if(a==0){
printf("Yes\n");continue;
}
bool flag=1;
int cnt=0;
int max=-10,min=10000000;
init();
while(1) {
vis[a]=1,vis[b]=1;
if(a<min) min=a;
else if(a>max) max=a;
if(b<min) min=b;
else if(b>max) max=b;
if(flag) { //flag==1还没成环,如果成环就不用浪费时间了
if(find(a)==find(b)) flag=0;//成环
else merge(a,b);
}
scanf("%d%d",&a,&b);
if(!a) break;
}
if(!flag) printf("No\n");
else{
for(int i=min;i<=max;i++){
if(vis[i] && f[i]==i) cnt++;//检查是否仅有一个并查集
}
if(cnt==1) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}