第一次接触并查集,所以是借鉴别人的;
思路(参考别人的):
如果符合小希的想法则需要满足如下两个条件:
1:保证图是连通的,且连通分量为1( 即从一点可以到任意一点 )
2:不存在环(包括自环)
因为这是一个无向图,只要保证 顶点数 = 边数+1 , 就可以说明是连通的。如果存在1->2 , 2->3 , 1->3这样的图话,虽然满足了左面的公式,但是已经成了环,所以也不会影响到最后的判断。
代码:
#include<stdio.h>
int x[100001],y[100001];
int find(int n)
{
if(n!=x[n])
{
x[n]=find(x[n]);
}
return x[n];
}
int main()
{
int a,b;
int vag,flag,tt;
while(~scanf("%d%d",&a,&b))
{
vag=0;flag=0,tt=0;
if(a==0&&b==0)
{
printf("Yes\n");
continue;
}
if(a==-1&&b==-1)
break;
int i;
for(i=0;i<=100000;i++)
{
x[i]=i;
y[i]=0;
}
a=find(a);
b=find(b);
if(a!=b)
{
x[a]=b;
flag++;
}
else
vag=1;
y[a]=1;
y[b]=1;
while(1)
{
scanf("%d%d",&a,&b);
if(a==0&&b==0)
break;
a=find(a);
b=find(b);
if(a!=b)
{
x[a]=b;
flag++;
}
else
vag=1;
y[a]=1;
y[b]=1;
}
for(i=1;i<=100000;i++)
if(y[i])
tt++;
if(!vag&&tt==flag+1)
printf("Yes\n");
else
printf("No\n");
}
}
再帖一个参考代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int M = 100005;
int a,b;
int father[M]; //记录父节点
bool circle; //判断是否存在环
bool visit[M]; //用来记录顶点数
int edgenum,vnum; //分别表示边数,顶点数
void initial( )
{
for( int i=0 ; i<M ; i++ )
father[i] = i,visit[i]=false;
circle = false;
edgenum = vnum = 0;
}
int find( int x )
{
return x == father[x] ? x : father[x] = find(father[x]); //找祖先节点 + 路径压缩
}
void merge( int a ,int b )
{
if( a == b )
circle = true;
int x , y;
x = find(a);
y = find(b);
if( x != y ){
father[x] = y;
edgenum++; //引出一条边
}
else
circle = true; //x==y,说明他们是同一个祖先,一旦连通便与祖先3者成环
}
int main()
{
while( true ){
initial( );
scanf("%d%d",&a,&b);
if( a==0 && b==0 ){ //为空树
printf("Yes\n");
continue;
}
if( a==-1 && b==-1 )
break;
visit[a] = true;
visit[b] = true;
merge( a,b );
while( true ){
scanf("%d%d",&a,&b);
if( a==0 && b==0 )
break;
visit[a] = true;
visit[b] = true;
merge( a , b );
}
for( int i=0 ; i<M ; i++ )
if( visit[i] )
vnum++;
if( !circle && edgenum+1 == vnum )
printf("Yes\n");
else
printf("No\n");
}
return 0;
}