这道题学到的东西:
- 判断是否成环:如果新加入一条边,且边上的两个点有共同的祖先,那就成环。
- 判断是否为森林:另开一个数组记录某个点是否出现过,遍历集合数组,如果该点出现过且为根节点(i=f[i]),那计数器就++。
思路:
看每组数据能否构成无环连通图。
1。推断成环:读入过程中,合并集合的时候,假设,当前读入的两个元素属于同一个集合。那么肯定是No。
2。推断连通:仅仅要推断根节点数为1就可以。
#include<iostream>
using namespace std;
const int maxn=100005;
int vis[maxn],f[maxn];
bool Flag=true;
// int find_f(int x){
// int a=x;//
// while(a!=f[a]) a=f[a];
// while(x!=f[x]){
// int z=f[x];//记录下来当前节点的父节点。
// f[x]=a;//压缩路径。
// x=z;
// }
// return a;
// }
int find_f(int x){
if(x==f[x]) return x;
else{
f[x]=find_f(f[x]);
return f[x];
}
}
void Merge(int a,int b){
int fa=find_f(a);
int fb=find_f(b);
if(fa==fb){
Flag=false;
}else{
f[fb]=fa;
}
}
int main(){
int a,b;
while(scanf("%d %d",&a,&b)){//输入每个数据集的的第一个数据。
Flag=true;
if(a==-1&&b==-1) break;
else if(a==0&&b==0){
printf("Yes\n");
continue;
}
//初始化集合数组以及标记数组。
for(int i=1;i<=maxn;i++) f[i]=i,vis[i]=0;
vis[a]=1; vis[b]=1;
Merge(a,b);
int c,d;
while(scanf("%d %d",&c,&d)){
if(c==0&&d==0) break;
vis[c]=1; vis[d]=1;
Merge(c,d);
}
// //计算集合的数量
// int cnt=0;
// for(int i=1;i<=maxn;i++){
// if(vis[i]&&f[i]==i) cnt++;
// if(cnt>=2) {
// Flag=false;
// break;
// }
// }
// if(!Flag){
// cout<<"No\n";
// continue;
// }else{
// cout<<"Yes\n";
// }
if(!Flag)
{
printf("No\n");
continue;
}
else
{
int cont=0;
for(int i=0;i<=100005;i++)
{
if(vis[i]&&f[i]==i)
cont++;
}
if(cont==1)
{
printf("Yes\n");
}
else
{
printf("No\n");
}
}
}
return 0;
}