hdu1325&&poj1308 Is It A Tree? 基础并查集

Is It A Tree?

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11616    Accepted Submission(s): 2672


Problem Description
A tree is a well-known data structure that is either empty (null, void, nothing) or is a set of one or more nodes connected by directed edges between nodes satisfying the following properties. 
There is exactly one node, called the root, to which no directed edges point. 

Every node except the root has exactly one edge pointing to it. 

There is a unique sequence of directed edges from the root to each node. 

For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.



In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not. 

 

Input
The input will consist of a sequence of descriptions (test cases) followed by a pair of negative integers. Each test case will consist of a sequence of edge descriptions followed by a pair of zeroes Each edge description will consist of a pair of integers; the first integer identifies the node from which the edge begins, and the second integer identifies the node to which the edge is directed. Node numbers will always be greater than zero. 
 

Output
For each test case display the line ``Case k is a tree." or the line ``Case k is not a tree.", where k corresponds to the test case number (they are sequentially numbered starting with 1). 
 

Sample Input
  
  
6 8 5 3 5 2 6 4 5 6 0 0 8 1 7 3 6 2 8 9 7 5 7 4 7 8 7 6 0 0 3 8 6 8 6 4 5 3 5 6 5 2 0 0 -1 -1
 

Sample Output
  
  
Case 1 is a tree. Case 2 is a tree. Case 3 is not a tree.



题意:看图就已经很清楚了。

思路:和hdu1272题一样,只不过这题题目是出的有向图,但是思路是一样的,判断方法也是一样的,输入合并的方向都是选的前连到后,

所以代码通用,


 
 
根据树的定义与特点,需考虑的情况有:树中节点至多只能有一个父节点;树中不能出现环;构成的图只能有一个根节点,否则构成的将是森林而不是一棵树
通过观察输入,输出可知,题中编号是随机的,所以在变成中要对出现的点标记才能判断。
Step1:对每对输入的根节点标记表示这些节点出现过并进行合并操作,合并操作时两个节点不能有相同的根节点否则将构成环;假设b节点要接到a上,则要保证b节点是一个根节点,否则若进行合并操作b将会有两个父节点;若无以上情况,则可以合并两棵树;
Step2:每组数据输入结束后要计算整个图中的根节点总数,若根节点总数不为1,则构成的图不是一棵树。
Step3:根据以上的判断就可以输出结果,每组结果输出后还要重新初始化数据。


#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
int f[1000000],flag[1000000];  
int find(int x)  
{  
    if(x!=f[x])  
        f[x]=find(f[x]);  
    return f[x];  
}  
int make(int a,int b)//make函数并操作时出现错误就返回1,正确返回0;  
{  
    int f1=find(a);  
    int f2=find(b);  
    if(f2!=b) //b链接在a上,则要保证b是个根节点,否则b将有两个父节点,这显然是错误的  
        return 1;  
    if(f1==f2)//如果a,b在同一颗树中,如果在进行并操作就会产生环,这显然也是错误的  
        return 1;  
    else  
        f[f2]=f1;  
    return 0;  
}  
  
int main()  
{  
    int a,b,key=0,p=1,i,max=0,t=0, k=1;  
    for(i=1; i<999999; i++)  
        f[i]=i;  
    memset(flag,0,sizeof(flag));  
    while(1)  
    {  
        scanf("%d%d",&a,&b);  
        if(a>max)max=a;  
        if(b>max)max=b;  
        if(a<=-1&&b<=-1)break;  
        if(a==0&&b==0)  //若a,b同时为0,则一组数据输入完毕,进行判断  
        {  
            for(i=1; i<=max; i++) //计算树根的数量是否大于等于2;  
            {  
                if(flag[i]==1&&f[i]==i) //flag[i]==1表示之前有输入  
                    t++;  
                if(t>=2)  //树根大于2,退出循环  
                    break;  
            }  
            if(key>0||t>=2)//出现不合法情况或者树根大于2则判断不能成为一颗树  
                printf("Case %d is not a tree.\n", k++);  
            else printf("Case %d is a tree.\n", k++);  
            for(i=1; i<=99999; i++) //结束输入则初始化变量  
                f[i]=i;  
            key=0;  
            t=0;  
            max=0;  
            memset(flag,0,sizeof(flag));  
            continue; //继续下一组数据  
        }  
        flag[a]=1;  
        flag[b]=1;  //对输入的编号进行标记,  
        key+=make(a,b);  //若出现不合法的情况, key的值就会大于0  
    }  
}  



代码2:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int LEN=100050;
int fa[LEN], vis[LEN];
int find_fa(int a)
{
    if( a==fa[a] )
        return fa[a];
    return fa[a]=find_fa(fa[a]);
}
int make(const int& a, const int& b)
{
    int pa=find_fa(a);
    int pb=find_fa(b);
    if( pb!=b ) return 1;
    if( pa==pb ) return 1;
    fa[pb]=pa;
    vis[a]=vis[b]=1;
    return 0;
}
int main()
{
    int a, b, key=0, i, j, mark=0, k=1;
    int max=-1;
    while( cin>>a>>b )
    {
        if( a<=-1 && b<=-1 ) break;
        mark=key=0;
        max=-1;
        for(i=0; i<LEN; i++)
            fa[i]=i, vis[i]=0;
        if( max<a ) max=a;
        if( max<b ) max=b;
        key+=make(a, b);
        while( cin>>a>>b )
        {
            if( a==0 && b==0 ) break;
            if( max<a ) max=a;
            if( max<b ) max=b;
            key+=make(a, b);
        }
        for(i=1; i<=max; i++)
        {
            if( vis[i] && fa[i]==i )
                mark++;
            if( mark>1 )
                break;
        }
        if( key>0 || mark>1 )
            printf("Case %d is not a tree.\n", k++);
        else printf("Case %d is a tree.\n", k++);
    }
    return 0;
}















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值