上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。
整个文件以两个-1结尾。
6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1
Yes YesNo
题意:
判断连接题中所给的点连接是否为一个无环无向连通图。
题解:
求出所有点中的最大值与最小值,并标记所有出现过的点。把所有点构成的路径都加入集合,并判断此路径是否已经连通。如果已连通则构成的图为有环。同时判断构成的图是否连通,如果存在两个或几个图不连通,即存在两个或几个集合,则不符合题意。注意输入只0 0的时候会输出Yes.
代码如下:
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; int f[100010]; int vis[100010]; int getf(int x)//寻找父节点,擒贼先擒王原则 { if(f[x]==x) return x; else { //路径压缩,每次返回时,顺便把遇到的点的父节点改为找到的父结点 //提高寻找速度 f[x]=getf(f[x]); return f[x]; } } int merg(int xx,int yy)//合并两个子集 { int t1=getf(xx);//寻找自己的父结点 int t2=getf(yy); if(t1!=t2)//靠左原则,左边的值变为右边的父节点, { f[t2]=t1; return 1;//表示xx,yy点未连通 } return 0; } int main() { int m,n,maxx,minn,s,flag; while(~scanf("%d%d",&m,&n)) { int i,sum=0; for(i=1; i<=100010; i++) f[i]=i; if(m==-1 && n==-1) break; if(m==0 && n==0) { printf("Yes\n"); continue; } maxx=0; flag=0; minn=99999999; s=1; s=merg(m,n); if(s==0) flag=1; vis[m]=1;//标记这个点出现过 vis[n]=1; maxx=max(m,maxx); maxx=max(n,maxx); minn=min(n,minn); minn=min(m,minn); while(scanf("%d%d",&m,&n)) { if(m==0 && n==0) break; s=merg(m,n); vis[m]=1; vis[n]=1; if(s==0) flag=1; maxx=max(m,maxx); maxx=max(n,maxx); minn=min(n,minn); minn=min(m,minn); } for(i=minn; i<=maxx; i++) { if(f[i]==i && vis[i]==1)//判断有几个父节点即有几个集合 sum++; } if(flag==1 || sum>1) printf("No\n"); else printf("Yes\n"); } }