题意:判断所给边组成的是否为连通图而且无环
解析:对于一个无环的连通图,有两个结论来判连通:1:仅有一个根节点,即只存在一个点i==pr[i]。
2:点数=边数+1
判环:初始的根节点均为自己。在联通的过程中,如果存在两个点的根节点相同,就说明从一个点要到达这个根节点,不止一条路可走。综上,单对判连通来讲,有两套解法可做。1:结尾遍历所有点,看是否仅有一个点等于其根节点。2:使用Set去重来记录点数,sum记录边数,输入结束看是否点数=边数+1。
此题细节颇多,仅输入 0 0,要输出Yes。
结论1:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; const int maxn=1e5+10; int pr[maxn],v[maxn]; int flag=0; void init() { for(int i=1;i<maxn;i++) { pr[i]=i; v[i]=0; } } int find(int x) { if(x!=pr[x]) return pr[x]=find(pr[x]); return x; } void join(int a,int b) { int fa=find(a),fb=find(b); if(fa!=fb) pr[fa]=fb; else flag=1; } int main() { int a,b; while(scanf("%d%d",&a,&b)) { flag=0; init(); v[a]=v[b]=1; if(a==-1&&b==-1) break; if(a==0&&b==0) { cout<<"Yes"<<endl;continue; } join(a,b); while(scanf("%d%d",&a,&b)) { if(a==0&&b==0) break; join(a,b); v[a]=v[b]=1; } if(flag==1) { cout<<"No"<<endl; } else { int ans=0; for(int i=1;i<maxn;i++) { if(v[i]==1&&pr[i]==i) ans++; if(ans>2) break; } if(ans==1) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } }
结论2:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<set> using namespace std; const int maxn=1e5+10; int pr[maxn],v[maxn]; int flag=0; void init() { for(int i=1;i<maxn;i++) { pr[i]=i; } } int find(int x) { if(x!=pr[x]) return pr[x]=find(pr[x]); return x; } void join(int a,int b) { int fa=find(a),fb=find(b); if(fa!=fb) pr[fa]=fb; else flag=1; } int main() { int a,b; while(scanf("%d%d",&a,&b)) { int sum=0; set<int>ss; flag=0; init(); ss.insert(a); ss.insert(b); join(a,b); sum++; if(a==-1&&b==-1) break; if(a==0&&b==0) { cout<<"Yes"<<endl;continue; } while(scanf("%d%d",&a,&b)) { if(a==0&&b==0) break; join(a,b); ss.insert(a);ss.insert(b); sum++; //貌似后台并没有输入重边的样例 } if(flag==1) { cout<<"No"<<endl; } else { if(ss.size()==sum+1) cout<<"Yes"<<endl; else cout<<"No"<<endl; } } }
原文:https://www.cnblogs.com/liyexin/p/12650463.html