Fork me on GitHub

树的判定两道题

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

 

 

posted @ 2013-12-30 17:43  whatbeg  阅读(334)  评论(0编辑  收藏  举报