Is It A Tree? (并查集)
思路:搞人的题,特判0 0 的时候 输出 "is a tree.",
存在回路的时候 输出 "is not a tree.",
存在两个联通分量的时候输出 "is not a tree."。也就是两个树的时候。
两个树要怎么判断呢
假设给出的所有的边,组成一棵树,利用并查集我们可以把他所有的子节点并到一个节点上,所以我们只要判断有多少节点的父亲是他本身就行了。如果大于1,就证明存在两个树(注意一点,不一定所有的点都压缩到极致,也就是所有的点都挂在一个节点上,他可能是间接的挂在这个根节点上)
就例如下面的运行结果。
有的点是间接和根节点4相连接的,但是我们发现根节点4的父亲是他本身,所以我们只要判断有多少节点的父节点是他本身就行了,如果超过一个就说明存在两个树,否则就是一棵树。
#include <iostream> using namespace std; int a,b,n; int pre[1000005]; int flage; int vis[1000005]; //标记数组,节点可能不是从1~n,所有要标记一下哪几个点出现过。 int cnt; int root( int x ){ if ( x!=pre[x] ) { pre[x] = root(pre[x]); } return pre[x]; } void join( int a, int b ){ int x = root(a); int y = root(b); if ( x==y ) { flage = 0; //表示出现环。 } else { pre[x] = y; } } int main() { int s = 1; while ( cin>>a>>b && a!=-1 && b!=-1 ) { if ( a==-1 && b==-1 ) { break ; } for ( int i=0; i<=100002; i++ ) { pre[i] = i; vis[i]=0; } cnt = 0; flage = 1; n = 0; join(a,b); vis[a]=1; vis[b]=1; if ( a==0 && b==0 ) { cout << "Case " << s++ << " is a tree." << endl; continue ; } while ( cin>>a>>b && a!=0 && b!=0 ) { join(a,b); vis[a]=1; vis[b]=1; } if(flage==0){ cout << "Case " << s++ << " is not a tree." << endl; continue; } int cntt = 0; for ( int i=0; i<100002; i++ ) { /*if(vis[i]==1) { cout<<"i "<<i<<" pre[i] "<<pre[i]<<endl; }*/ if (pre[i]==i&&vis[i]==1) { cnt++; //判断有几棵树 } } if ( cnt==1) { cout << "Case " << s++ << " is a tree." << endl; } else { cout << "Case " << s++ << " is not a tree." << endl; } } return 0; }