zoukankan      html  css  js  c++  java
  • Is It A Tree?(并查集)(dfs也可以解决)

    Is It A Tree?
    Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u
    Submit Status

    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.


    题意:给定一定关系,判断其是否是一棵树,注意,空树也是一棵树,不能有成环的情况,不能是森林,不能有入度为2的节点。
    下面给出两种思路:
    1,并查集:维护一个森林 每输入一组关系(边)的时候,将这两个点连起来看做一棵树,如果可以将其合并到其他的树上的话就将其合并,并且树的总数目加1;
    (注意: 只有当第二个端点值在其他树上是根节点的时候才能合并仍保持是一棵树,及从第一个端点指向第二个端点的时候会保证不会出现入度为2的点)
    如果不满足合并条件的时候就将定义的树的总数加1,中间过程有可能再将这两棵树连起来,所有操作完成后,统计树的个数,要是树的棵树大于1的话则所给点不能构成一棵树
    注意要排除自成环的情况,和空树的情况。
    2,dfs:
     将所有的边用链接表的方式存起来,当按照正常的顺序扫描一遍的时候如果是一个符合条件的树的话就不会存在一个点被访问两次,即扫描的时候不会出现visit数组被标记为走过的情况
    而且当以任一点为开始扫描完一遍的时候不存在没有扫描过的点,因为不存在森林。
    这里同样要考虑空树的情况。

     1 /**
     2     ---------------------------------------------------
     3         HuHanwu
     4         2012-7-12
     5         并查集快速判断每次输入是破坏树的性质
     6         时间复杂度: o(n) n为节点的个数
     7     ---------------------------------------------------
     8 */
     9 #include <iostream>
    10 #include <cstdio>
    11 #include <cstring>
    12 using namespace std;
    13 #define MAXN 1000002
    14 
    15 int p[MAXN];    //存放父亲节点 只要存在父亲节点则此节点一存在某棵树中
    16 int find(int x){ return p[x]==x ? x :(p[x]=find(p[x]));}    //查找父亲节点并 压缩路径
    17 
    18 int main()
    19 {
    20     int a,b,tree_num,t=0,father_a,father_b,TF; //tree_num 保存当前的树的棵数
    21     while(~scanf("%d%d",&a,&b) && (a>=0||b>=0))
    22     {
    23         tree_num=TF=1;
    24         if(a==0)
    25         {
    26             printf("Case %d is a tree.
    ",++t);
    27             continue;
    28         }//空树也是一棵树 
    29         if(a==b)
    30             TF=0;//不能成环 
    31         else
    32         {
    33             memset(p,0,sizeof(p));  //用 0 初始化所有节点的父亲节点
    34             p[a]=p[b]=a;
    35         }
    36         while(~scanf("%d%d",&a,&b) && a!=0)
    37         {
    38             if(TF==0 ) // 只要已经判断出该森林已经不是树
    39                 continue;
    40             if(p[b]!=0) // b节点已经存在
    41             {
    42                 father_b=find(b);
    43                 if(b!=father_b) // b 节点不是树根就不可以连成一棵树
    44                 {
    45                     TF=0;
    46                     continue;
    47                 }
    48                 else//下面都是当b 为树根的情况 
    49                 {
    50                     if(p[a]!=0) // a b 节点都存在则树的的棵数-1
    51                     {
    52                         p[b]=find(a);//将两棵树连起来,只有当b是父节点的时候才可以这么连 
    53                         tree_num--;
    54                     }
    55                     else        //a 节点不存在 而 b 节点存在
    56                         p[b]=p[a]=a;
    57                 }
    58             }
    59             else
    60             {
    61                 if(p[a]==0) // a b 节点都不存在则树的棵数+1
    62                 {
    63                     p[a]=p[b]=a;
    64                     tree_num++;
    65                 }
    66                 else        //a 节点存在 而 b 节点不存在
    67                     p[b]=find(a);
    68             }
    69         }
    70         printf("Case %d ",++t);
    71         if(TF==0)
    72         {
    73             printf("is not a tree.
    ");
    74             continue;
    75         }
    76         if(tree_num==1)      // 树的棵数是否为1
    77             printf("is a tree.
    ");
    78         else
    79             printf("is not a tree.
    ");
    80     }
    81     return 0;
    82 }

    下面给出dfs代码,其中用链表存放边

      1 #include <cstdio>
      2 #include <map> 
      3 #include <cstring>
      4 using namespace std;
      5 #define N 50005
      6 
      7 int head[N];
      8 struct Edge{
      9     int v, next;
     10 }edge[N*20];
     11 int Ecnt;
     12 
     13 void init()
     14 {
     15     Ecnt = 0;
     16     memset(head, -1, sizeof(head));
     17 }
     18 
     19 void add(int u, int v)
     20 {
     21     edge[Ecnt].v = v;
     22     edge[Ecnt].next = head[u];
     23     head[u] = Ecnt++;
     24 }
     25 
     26 bool visited[N]; 
     27 bool dfs(int u)
     28 {
     29     for(int i = head[u]; i != -1; i = edge[i].next)
     30     {
     31         int v = edge[i].v;
     32         if(visited[v]) return false;
     33         visited[v] = 1;
     34         int res = dfs(v);
     35         if(res == false) return false;
     36     }
     37     return true;
     38 }
     39 
     40 struct Node {
     41     int s, t;
     42 }node[N];
     43 
     44 
     45 map<int, int>mp;
     46 
     47 int in[N];
     48 int main()
     49 {
     50     int s, t, cas = 0;
     51     while(~scanf("%d %d", &s, &t))
     52     {
     53         cas++;
     54         if(s == 0 && t == 0){
     55             printf("Case %d is a tree.
    ", cas);
     56             continue;
     57         }
     58         if(s < 0 && t < 0) break;
     59         int c = 0;
     60         node[c].s = s, node[c++].t = t;
     61         while(~scanf("%d %d", &s, &t), s||t)
     62             node[c].s = s, node[c++].t = t;
     63        
     64         mp.clear();
     65         int n = 0;//结点总数 
     66         for(int i = 0; i < c; i++)
     67         {
     68             s = node[i].s, t = node[i].t;
     69             if(mp.find(s) == mp.end()) mp[s] = n++;
     70             if(mp.find(t) == mp.end()) mp[t] = n++;
     71             node[i].s = mp[s];
     72             node[i].t = mp[t];
     73         }
     74         init();
     75         memset(in, 0, sizeof(in));
     76         for(int i = 0; i < c; i++)
     77         {
     78             s = node[i].s, t = node[i].t;
     79             add(s, t);
     80             in[t]++;
     81         }
     82         bool ans = true;
     83         int root = -1;
     84         for(int i = 0; i < n; i++) 
     85         {
     86             if(in[i] == 0)
     87             {
     88                 if(root == -1) root = i;
     89                 else ans = false;
     90             }
     91         }
     92         if(ans == false || root == -1)
     93         {
     94             printf("Case %d is not a tree.
    ", cas);
     95             ans = false;
     96             continue;
     97         }
     98         memset(visited, 0, sizeof(visited));
     99         visited[root] = 1;
    100         ans = dfs(root);
    101         if(ans == false)
    102         {
    103             printf("Case %d is not a tree.
    ", cas);
    104             ans = false;
    105             continue;
    106         }
    107         for(int i = 0; i < n; i++) 
    108             if(!visited[i])
    109             {
    110                 printf("Case %d is not a tree.
    ", cas);
    111                 ans = false;
    112                 break;
    113             }
    114         if(ans)printf("Case %d is a tree.
    ", cas);
    115     }
    116 }
  • 相关阅读:
    剑指Offer对答如流系列
    剑指Offer对答如流系列
    KMP算法
    殊途同归
    从m个数中取top n
    用红黑树实现500万数据的动态排序
    返璞归真
    second blog编程之美------控制cpu曲线
    first blog编程之美-----计算1的个数
    mathematica入门学习记录:
  • 原文地址:https://www.cnblogs.com/shanyr/p/4650840.html
Copyright © 2011-2022 走看看