poj1308(并查集)

题目链接:http://poj.org/problem;jsessionid=436A34AE4BE856FB2DF9B264DCA9AA4E?id=1308

题意:给定一些边让你判断是否构成数。

思路:这道题细节很多,wa了好久。利用并查集将一棵树的节点并在一块,如果当前的边的两个端点祖先相同,则不能够成树(有环),利用num数组记录每个结点的入度,入度不能大于1。输入为 0 0表示空树,满足条件。可能出现森林,所以用vector记录出现的结点编号,最后判断所有结点是否有相同的祖先。还有不能存在i i,即指向自己的边。

AC代码:

#include<cstdio>
#include<vector>
using namespace std;

const int maxn=1e6+5;
int root[maxn],num[maxn],t1,t2,flag,cas=1;
vector<int> v;

int getr(int k){
    if(root[k]==k) return k;
    else return root[k]=getr(root[k]);
}

int main(){
    while(~scanf("%d%d",&t1,&t2)&&t1>=0){
        if(!t1){
            printf("Case %d is a tree.\n",cas++);
            continue;
        }
        v.clear();
        v.push_back(t1);
        v.push_back(t2);
        for(int i=1;i<=1000000;++i)
            root[i]=i,num[i]=0;
        flag=1;
        if(t1==t2) flag=0;
        int r1=getr(t1),r2=getr(t2);
        root[r2]=r1,++num[t2];
        while(~scanf("%d%d",&t1,&t2)&&t1){    
            if(flag){
                v.push_back(t1);
                v.push_back(t2);
                r1=getr(t1),r2=getr(t2);        
                if(r1!=r2&&!num[t2]&&t1!=t2)
                    root[r2]=r1,++num[t2];
                else
                    flag=0;
            }
        }
        if(flag){
            int r=getr(v[0]);
            for(int i=1;i<v.size();++i)
                if(getr(v[i])!=r){
                    flag=0;
                    break;
                }
        }
        if(flag)
            printf("Case %d is a tree.\n",cas++);
        else 
            printf("Case %d is not a tree.\n",cas++);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/FrankChen831X/p/10667201.html