并查集的基础题,输入时判断一下两个点的根节点是否已经联通,如果已经联通那么说明迷宫不符合要求,需要注意2点:
1.当直接输入0 0时这时直接输出Yes,进行下一次输入,因为0 0也满足题目的要求。
2.迷宫必须是联通的1 2 3 4 0 0这组样例是错误的,因为迷宫两处被分开.
1的解决办法很简单直接判断就行,2就要记录一下每个点所在的集合的点的数目,首先点的总数应该记下,这个很好判断,开一个数组全部赋值为0,当两个点输入时判断一下两个点是否出现过,即a[x],a[y]是否等于0,等于0则点的总数加一,a[x],a[y]也加一。当判断发现两个点的根节点不联通时,合并根节点时也合并两个集合的点的数目,每个集合刚开始时的数目是1,合并集合时把数目也合并起来,我的代码是合并给大的那个根节点。代码如下:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100050;
int pre[maxn],num[maxn],a[maxn];
void creat()
{
for(int i=0;i<=maxn;i++)
{
pre[i]=i;
num[i]=1;
}
}
int findroot(int root)
{
int son=root,tmp;
while(root!=pre[root])
root=pre[root];
while(son!=pre[son])
{
tmp=pre[son];
pre[son]=root;
son=tmp;
}
return root;
}
int main()
{
int n,m,x,y,flag=0;
int sum=0;
while(scanf("%d %d",&n,&m)==2&&n!=-1&&m!=-1)
{
if(!n&&!m)
{
puts("Yes");
continue;
}
int nn=n;
flag=0;
sum=0;
memset(a,0,sizeof(a));
if(a[n]==0)
{
sum++;
a[n]++;
}
if(a[m]==0)
{
sum++;
a[m]++;
}
creat();
int root1=findroot(n);
int root2=findroot(m);
if(n<m)
swap(n,m);
pre[m]=n;
num[n]+=num[m];
while(scanf("%d %d",&n,&m)==2&&n&&m)
{
if(a[n]==0)
{
sum++;
a[n]++;
}
if(a[m]==0)
{
sum++;
a[m]++;
}
root1=findroot(n);
root2=findroot(m);
if(root1==root2)
{
flag=1;
}
if(root1<root2)
swap(root1,root2);
pre[root2]=root1;
num[root1]+=num[root2];
}
int tmp=findroot(nn);
//printf("%d %d %d %d\n",sum,num[tmp],tmp,nn);
if(flag==1||num[tmp]!=sum)
puts("No");
else
puts("Yes");
}
return 0;
}