树的判定两道题

1.判断有向图是否是树

POJ 1308 --- Is It A Tree ?    

题目链接: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=39051#problem/G

 

有向图是否为树的判断条件:

1.树中每个节点至多只能有一个父节点。

2.树中不能出现环。

3.树中只能有一个根节点。

 

用并查集来解,则条件转化为:

1'.一个节点要连接到另一个节点的后面,则该节点必须是根节点,否则会出现两个根节点的情况。

2'.如果两个节点已经属于同一个集合,则不能在合并,否则会出现环。

3'.最后统计根节点(fa[i] == i)的个数,如果大于一个,则不是树。

 

代码:

#include <iostream>

#include <cstdio>

#include <cmath>

#include <algorithm>

using namespace std;

#define N 1000100



int fa[N],flag[N];



void makeset(int n)

{

    for(int i=1;i<=n;i++)

    {

        fa[i] = i;

        flag[i] = 0;

    }

}



int findset(int x)

{

    if(x != fa[x])

    {

        fa[x] = findset(fa[x]);

    }

    return fa[x];

}



int unionset(int a,int b)

{

    int x = findset(a);

    int y = findset(b);   //b永远是a的子节点

    if(x == y)            //已经是一个集合,再合并会形成环

        return 1;

    if(fa[y] != b)         //b不是根节点

        return 1;

    else

    {

        fa[y] = x;

        return 0;

    }

}



int main()

{

    int a,b,i,maxi,gen,bad;

    int cs = 1;

    bad = 0;

    maxi = 0;

    makeset(N-1);

    while(1)

    {

        scanf("%d%d",&a,&b);

        if(a == -1 && b == -1)

            break;

        maxi = max(maxi,max(a,b));

        if(a == 0 && b == 0)

        {

            gen = 0;

            for(i=1;i<=maxi;i++)

            {

                if(flag[i] == 1 && fa[i] == i)  //是否根节点 

                {

                    gen++;

                }

                if(gen>1)

                    break;

            }

            if(gen>1 || bad>0)

                printf("Case %d is not a tree.\n",cs++);

            else

                printf("Case %d is a tree.\n",cs++);

            bad = 0;

            maxi = 0;

            makeset(N-1);

        }

        else

        {

            flag[a] = flag[b] = 1;

            bad += unionset(a,b);

        }

    }

    return 0;

}
View Code

 

 

你可能感兴趣的:(树)