首页 > 代码库 > hdu 1325 && poj 1308 Is It A Tree?

hdu 1325 && poj 1308 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): 13596    Accepted Submission(s): 3034


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 45 6 0 08 1 7 3 6 2 8 9 7 57 4 7 8 7 6 0 03 8 6 8 6 45 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.
 

 

          这道题,一开始我是想用边的数量来判断它是否是一棵树,到最后代码运行时才发现不可以,然后到网上才知道,这道题其实使用树的特性和并查集的一些特点来解决的。

因为树的任意一节点的入度都为1,有且仅有一个根节点,那个根节点的父亲就是它自己,这里用到了并查集的特点吧,如果输入的不止一棵树的话,那么它就有不止一个根节点吧。根节点的入度是为0的,而且不能构成环吧。但这道题hdu上有,poj上也有,感觉poj的数据测试要更加严格一些。

 

hdu上可以过的代码:

#include <stdio.h>struct node       {    int use;       //表示是否用过这个节点,0表示没有用过,1表示用过    int father    //存储它的父亲节点的位置    int num       //存储节点的入度};struct node Node[100005];void MakeSet(int n)       //将结构体数组进行初始化{    for(int i = 0; i<=n; i++)    {        Node[i].use = 0;        Node[i].father = i;        Node[i].num = 0;    }}int FindSet(int x)       //查找父亲节点{    if(x != Node[x].father)    {        Node[x].father = FindSet(Node[x].father);    }    return Node[x].father;}void UnionSet(int a, int b)         //将2个集合进行合并{    int x = FindSet(a);    int y = FindSet(b);    if(x == y)        return ;    else        Node[y].father = x;}int main(){    int a, b;    int k = 1, flag = 1, mark;        //flag变量表示是否是一棵树    MakeSet(100000);    while(scanf("%d%d", &a, &b)!=EOF && (a!=-1 || b!=-1))    {        if(a==0 && b==0)        {            mark = 0;            for(int i = 1; i<=100000; i++)            {                if(Node[i].use==1 && Node[i].num>1)     //查找使用过的节点的度,如果有大于1的,则表明不是一棵树                {                    flag = 0;                    break ;                }                if(Node[i].use==1 && Node[i].father==i)     //查找有几个根节点                    mark++;            }            if(mark > 1)                flag = 0;            if(flag)                printf("Case %d is a tree.\n", k++);            else                printf("Case %d is not a tree.\n", k++);            MakeSet(100000);            flag = 1;        }        else        {            Node[a].use = 1;    Node[b].use = 1;            Node[b].num++;            UnionSet(a, b);        }    }    return 0;}

 

 

poj上可以过的代码:

#include <stdio.h>struct node{    int use;    int father;    int num;};struct node Node[100005];void MakeSet(int n){    for(int i = 0; i<=n; i++)    {        Node[i].use = 0;        Node[i].father = i;        Node[i].num = 0;    }}int FindSet(int x){    if(x != Node[x].father)    {        Node[x].father = FindSet(Node[x].father);    }    return Node[x].father;}void UnionSet(int a, int b){    int x = FindSet(a);    int y = FindSet(b);    if(x == y)        return ;    else        Node[y].father = x;}int main(){    int a, b;    int k = 1, flag = 1, mark;    MakeSet(100000);    while(scanf("%d%d", &a, &b)!=EOF && (a!=-1 || b!=-1))    {        if(a==0 && b==0)        {            mark = 0;            for(int i = 1; i<=100000; i++)            {                if(Node[i].use==1 && Node[i].num>1)                {                    flag = 0;                    break ;                }                if(Node[i].use==1 && Node[i].father==i)                    mark++;            }            if(mark > 1)                flag = 0;            if(flag)                printf("Case %d is a tree.\n", k++);            else                printf("Case %d is not a tree.\n", k++);            MakeSet(100000);            flag = 1;        }        else if(a == b || (a!=b && FindSet(a)==FindSet(b)))    //多了一个这个判断,就是自己不能为自己的父亲节点,且不能构成环        {            flag = 0;        }        else        {            Node[a].use = 1;    Node[b].use = 1;            Node[b].num++;            UnionSet(a, b);        }    }    return 0;}