并查集判断无环联通图
HDU1272小希的迷宫
大致题意:给出很多条无向边,要求任意两点间可通且仅有一条路径可通,如果不行输出no。
比如说这个图
1,2,3,4的根都是1。
5,6,7的根都是5。
如果把2和4,3和4,1和3,5和7连接起来的话,就不满足仅有一条路径这个条件了,由此可见题目一个要求是保证无环。
但是仅仅这样还不够,因为我们发现无法从3到7,所以这个图必须是联通的
见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
using namespace std;
const int maxn=1e5+7;
int flag;
int fa[maxn];
int vis[maxn];
int a,b,c,d;
void init(int n)
{
for (int i=1; i<=n; i++)
{
fa[i]=i;
}
flag=0;
memset(vis,0,sizeof vis);
}
int find(int x)
{
if (fa[x]!=x)
{
return fa[x]=find(fa[x]);
}
return fa[x];
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
//cout<<find(x)<<" "<<find(y)<<endl;
if (x==y)
{
flag=1;//有环
}
else
{
fa[y]=x;
}
}
int main()
{
while(~scanf("%d%d",&a,&b))
{
init(maxn);
if (a==-1&&b==-1)
break;
else if (a==0&&b==0)
{
cout<<"Yes"<<endl;
continue;
}
else
{
unite(a,b);
vis[a]=1;
vis[b]=1;
}
while(~scanf("%d%d",&c,&d)&&c&&d)
{
unite(c,d);
vis[c]=1;
vis[d]=1;
}
if (flag)
cout<<"No"<<endl;
else
{
int cnt=0;
for (int i=1; i<=maxn; i++)
{
if (vis[i]==1&&fa[i]==i)
{
cnt++;//判断有多少个树根
}
}
if (cnt==1)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
}
HDU1325 Is it a tree?
大致题意:判断这棵树是否具有以下特点:
1.是空树,如果不是空树则只能有一个根
2.所有非根子节点有且仅有一个父亲节点
3.树上无环
思路:
跟上面那题几乎一样,并查集判断无环和一个根,无非是多了个判断2号特点
可以用fa[x]和x来判断,如果fa[x]等于x就说明这个点还没被连过,如果fa[x]!=x但是又去连了一条,这样就相当于x有两个父亲节点就可以直接输出no了
见代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<vector>
#include<stack>
#include<bitset>
#include<cstdlib>
#include<cmath>
#include<set>
#include<list>
#include<deque>
#include<queue>
#include<map>
#define ll long long
#define pb push_back
using namespace std;
const int maxn=1e4+7;
int fa[maxn];
int vis[maxn];
int flag,num;
void init(int x)
{
for (int i=1; i<=x; i++)
{
fa[i]=i;
}
flag=0;
num=0;
memset(vis,0,sizeof vis);
}
int find(int x)
{
if (fa[x]!=x)
return fa[x]=find(fa[x]);
return fa[x];
}
void unite(int x,int y)
{
if (fa[y]!=y)
flag=1;
else
{
x=find(x);
y=find(y);
if (x==y)
flag=1;
else
fa[y]=x;
}
}
int main()
{
int K=1,a,b,c,d;
while(~scanf("%d%d",&a,&b))
{
if (a==-1&&b==-1)
break;
else if (a==0&&b==0)
{
printf("Case %d is a tree.\n",K);
K++;
continue;
}
init(maxn);
unite(a,b);
vis[a]=1;
vis[b]=1;
while(~scanf("%d%d",&c,&d)&&c&&d)
{
unite(c,d);
vis[c]=1;
vis[d]=1;
}
if (flag)
printf("Case %d is not a tree.\n",K);
else
{
for (int i=1; i<=maxn; i++)
{
if (vis[i]==1&&fa[i]==i)
{
num++;
}
}
if (num==1)
printf("Case %d is a tree.\n",K);
else
printf("Case %d is not a tree.\n",K);
}
K++;
}
return 0;
}