上次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 Yes No
这是一道并查集问题。有一点弯,不会的可以先找出畅通工程先做一下。
下面我就说一下思路
这道题的要求是只有一个根节点,并且没有回路,就是没有根节点相同的情况。
int pre[100010]; int s[100010]; int ans; //定义全局变量, int Find(int x) //查找函数 { int r=x; while(pre[r]!=r) r=pre[r]; int i=x,j; while(pre[i]!=r) { j=pre[i]; pre[i]=r; i=j; } return r; } bool mix(int x,int y) //并在一起的函数。 { int fx=Find(x); int fy=Find(y); if(fx!=fy) pre[fy]=fx; else ans=0; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { for(int i=1;i<=100010;i++) //这一步一定要放在(使用)mix 函数的前面,不然 s[i]=0,pre[i]=i; //会出错。 if(n==-1&&m==-1) break; if(n==0&&m==0) { printf("Yes\n"); continue; } int mi,ma;ans=1; mi=min(n,m),ma=max(n,m); mix(n,m); s[n]=1,s[m]=1; while(scanf("%d%d",&n,&m)&&(n||m)) { int x,y; x=min(n,m),y=max(n,m); if(x<mi)mi=x; if(y>ma)ma=y; mix(n,m); s[n]=1,s[m]=1; } if(!ans) printf("No\n"); //先进行判断一下,也可以不判断,在下面再进行判断。 else { int k,i; for(k=0,i=mi;i<=ma;i++) //k是判断根节点的个数 { if(s[i]&&pre[i]==i) k++; if(k>1) { ans=0; break; } } if(ans) printf("Yes\n"); else printf("No\n"); } } }
做题还是要多注意细节,如果不注意,几个小时就检查那一点错误,太可惜了。
一年后了,自己成长了很多,在一次做这道题感触颇多 ,自己考虑了节点,但是没有考虑到,分开的情况。失误啊,还是要理解,不能敲模板啊。。。。
代码:::::
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<queue> #include<math.h> #include<iostream> const int inf=0x3f3f3f3f; using namespace std; int pre[100005]; int vis[100005]; int flag; int Find(int x) { int r=x; while(pre[r]!=r) { r=pre[r]; } int i=x,j; while(i!=r) { j=pre[i]; pre[i]=r; i=j; } return r; } void join(int x,int y) { int fx=Find(x); int fy=Find(y); if(fx!=fy) pre[fx]=fy; else flag=1; } int main() { int n,m; while(~scanf("%d%d",&n,&m)) { if(n==-1&&m==-1) break; if(n==0&&m==0) { printf("Yes\n"); continue; } for(int i=1;i<=100004;i++) { pre[i]=i; vis[i]=0; } int n1,m1;flag=0; join(n,m); vis[n]=1; vis[m]=1; while(scanf("%d%d",&n1,&m1)&&n1&&m1) { vis[n1]=1; vis[m1]=1; join(n1,m1); } int k=0; for(int i=1;i<=100004;i++) //完全可以暴力一下,le5不会超时。 if(vis[i]&&pre[i]==i) k++; if(k>1)flag=1; if(flag==1) printf("No\n"); else printf("Yes\n"); } }