题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1272
小希的迷宫
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22383 Accepted Submission(s): 6841
Problem Description
上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走。但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B,那么既可以通过它从房间A走到房间B,也可以通过它从房间B走到房间A,为了提高难度,小希希望任意两个房间有且仅有一条路径可以相通(除非走了回头路)。小希现在把她的设计图给你,让你帮忙判断她的设计图是否符合她的设计思路。比如下面的例子,前两个是符合条件的,但是最后一个却有两种方法从5到达8。
Input
输入包含多组数据,每组数据是一个以0 0结尾的整数对列表,表示了一条通道连接的两个房间的编号。房间的编号至少为1,且不超过100000。每两组数据之间有一个空行。
整个文件以两个-1结尾。
整个文件以两个-1结尾。
Output
对于输入的每一组数据,输出仅包括一行。如果该迷宫符合小希的思路,那么输出"Yes",否则输出"No"。
Sample Input
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
Sample Output
Yes
Yes
No
分析:
1:这道题 , 不满意的答案是, 有环路 ,或者有多个连通分量。 如果输入的两个点的根节点一样,则表示有回路。 如果根节点的数目不止1个(或者顶点数 != 边+1),表示有多个连通分量。输出 “No”。:
2: 这道题 wa了无数次, 居然是把“Yes” ,输出成“YES” ,谨记这种错误,避免以后再犯。
3:设置的量比较多, 考虑的比较复杂。
代码如下:
一: 通过判断根节点的个数。
1 #include<iostream> 2 #include<stdio.h> 3 #include<string> 4 #include<string.h> 5 #include<map> 6 #include<math.h> 7 #define Max(x,y) x>y?x:y 8 #define N 100005 9 using namespace std; 10 int vy[N]; 11 int ux[N]; 12 int parent[N]; 13 int flag[N]; // 标记已经访问过的点 14 int Find(int x) 15 { 16 if(x== parent[x]) return x; 17 parent[x]= Find(parent[x]); 18 return parent[x]; 19 } 20 void Union(int x, int y) 21 { 22 int xf=Find(x); 23 int yf=Find(y); 24 parent[xf]=yf; 25 } 26 int main() 27 { 28 int x,y,i,j,len,title; 29 int maxtmp; 30 while(scanf("%d%d",&x,&y)!=EOF && x!= -1 &&y!=-1) 31 { 32 i=j=0; 33 title=0; 34 maxtmp=0; 35 ux[0]=x; 36 vy[0]=y; 37 if(x==0 && y==0){ 38 printf("Yes "); 39 continue; 40 } 41 memset(flag,0,sizeof(flag)); 42 flag[x]=flag[y]=1; 43 maxtmp=Max(maxtmp,x); 44 maxtmp=Max(maxtmp,y); 45 while(scanf("%d%d",&x,&y)!=EOF && x && y) 46 { 47 48 ux[++i]=x; 49 vy[++j]=y; 50 flag[x]=flag[y]=1; 51 maxtmp=Max(maxtmp,x); 52 maxtmp=Max(maxtmp,y); 53 } 54 55 len=i+1; 56 for( i=1;i<=maxtmp;i++) //初始化 57 { 58 parent[i]=i; 59 } 60 for( i=0;i<len;i++) 61 { 62 if(Find(ux[i]) != Find(vy[i])) //查找 63 { 64 Union(ux[i],vy[i]); //合并 65 } 66 else 67 title=1; // 表示根节点相同,形成回路 68 } 69 if(title==1){ 70 printf("No "); 71 continue; 72 } 73 for(i=1;i<=maxtmp;i++) 74 { 75 if(flag[i] && Find(i)==i ) 76 title++; // 表示根节点的个数,只有1个就ok, 否则有多个连通分量 77 } 78 if(title == 1) 79 printf("Yes "); 80 else printf("No "); 81 } 82 return 0 ; 83 }
二: 通过判断 顶点个数 = 边数+1
#include<iostream> #include<stdio.h> #include<string> #include<string.h> #include<map> #include<math.h> #define Max(x,y) x>y?x:y #define N 100005 using namespace std; int vy[N]; int ux[N]; int parent[N]; int flag[N]; // 标记已经访问过的点 int Find(int x) { if(x== parent[x]) return x; parent[x]= Find(parent[x]); return parent[x]; } void Union(int x, int y) { int xf=Find(x); int yf=Find(y); parent[xf]=yf; } int main() { int x,y,i,j,len,title; int maxtmp; while(scanf("%d%d",&x,&y)!=EOF && x!= -1 &&y!=-1) { i=j=0; title=0; maxtmp=0; int total=0; ux[0]=x; vy[0]=y; if(x==0 && y==0){ printf("Yes "); continue; } memset(flag,0,sizeof(flag)); flag[x]=flag[y]=1; maxtmp=Max(maxtmp,x); maxtmp=Max(maxtmp,y); while(scanf("%d%d",&x,&y)!=EOF && x && y) { ux[++i]=x; vy[++j]=y; flag[x]=flag[y]=1; maxtmp=Max(maxtmp,x); maxtmp=Max(maxtmp,y); } len=i+1; for( i=1;i<=maxtmp;i++) //初始化 { parent[i]=i; } for( i=0;i<len;i++) { if(Find(ux[i]) != Find(vy[i])) //查找 { Union(ux[i],vy[i]); //合并 total++; // 记录 边的个数 } else title=1; // 表示根节点相同,形成回路 } if(title==1){ printf("No "); continue; } for(i=1;i<=maxtmp;i++) { if(flag[i] ) title++; // 记录顶点个数 } if(title == total+1) printf("Yes "); else printf("No "); } return 0 ; }