题意:给定两个数,这两个数之间连有一条通路,以0,0作为一组数据的结束,以-1,-1作为整体结束,让你判断是否每两个点之间只有一条通路。
思路:每两个点之间要连通(即有关系),由此想到并查集,利用并查集找祖宗(根节点)的方式合并这些给定的点,而且,要满足只有一条通路,那么这集合中不能出现环,(一旦出现环就意味着出现有两点之间出现了多条通路,自己画画看),可以用一个标记flag来判断是否出现环路(出现环路的话就是找祖宗(根节点)时两个点有同一个祖宗(根节点))。
此题还有一个坑点,如果出现两个或以上集合时,一定有两个点不连通,此时是不满足题意的,可以用一个数组vis标记有那些点出现过,然后看看是否出现过的所有点都只有唯一的祖宗。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int maxn=100006; 6 bool flag; 7 int f[maxn]; 8 int vis[maxn]; 9 int find(int v)//并查集寻找根节点 10 { 11 if(f[v]==v) 12 return v; 13 else 14 return find(f[v]); 15 } 16 void merge(int u,int v)//合并 17 { 18 int t1=find(u); 19 int t2=find(v); 20 if(t1!=t2)//两个点的根节点不同,意味着两点属于不同集合 21 { 22 f[t2]=t1; 23 } 24 else//如果两个点已经在同一个集合(有同一个根节点),就说明已经有一条路将两点相连,再有就不符合题意了 25 { 26 flag=false; 27 } 28 } 29 int main() 30 { 31 int x,y; 32 while(~scanf("%d%d",&x,&y))//题目要求多组输入,先输入两个数是为了对应下面的特判 33 { 34 if(x==0&&y==0)//本题的特判,如果只输入了0,0,也是符合要求的,试出来的... 35 { 36 printf("Yes "); 37 continue;//需要继续输入下一组数据 38 } 39 for(int i=0;i<=maxn;i++)//每次输入新的一组数据时都要初始化 40 { 41 f[i]=i;//并查集初始化 42 vis[i]=0;//标记出现过的点 43 } 44 if(x==-1&&y==-1)//输入-1,-1结束 45 break; 46 merge(x,y);//合并两个点入一个集合 47 flag=true;//这是判断是否有环路出现的标志 48 vis[x]=1; 49 vis[y]=1;//将先输入的两点先标记 50 while(scanf("%d%d",&x,&y),x,y) 51 { 52 merge(x,y);//合并 53 vis[x]=1;//标记 54 vis[y]=1; 55 } 56 if(!flag) 57 { 58 printf("No ");//有环路,则不符合要求 59 continue;//继续下一组数据 60 } 61 else//在没有环路的前提下再判断其他情况 62 { 63 int cnt=0;//判断有几个集合 64 for(int i=0;i<=maxn;i++) 65 { 66 if(vis[i]&&f[i]==i)//在已经(给出)出现的点中有几个根节点是自己就有几个集合 67 cnt++; 68 } 69 if(cnt==1) 70 { 71 printf("Yes ");//当只有一个集合时,符合题意 72 } 73 else 74 { 75 printf("No ");//否则不符 76 } 77 } 78 } 79 }