机试练习05:poj1308——Is It A Tree?

一、题解方法

这道题还是应用的并查集的方法。

考虑不是一棵树的情况:

  1. 形成环,无根,即每个节点的入度为0。
  2. 有多个根,即形成森林。
  3. 节点有多个父节点,即节点的入度>1。

用并查集求解:

  1. 判断当前有向边的两端点是否在同一个集合内,若在,则一定存在环,则不存在这样的一棵树;若不在,进行其他判断。
  2. 对于多个父节点的判断,可以统计每个节点的入度,若入度>1,则不存在这样的一棵树;若不在,进行其他判断。
  3. 设置两个维护的变量,cnt保存节点总数,ans保存所有有效边的数量,即有向边两端点不在同一集合内。(参考上道并查集解决连通的问题)

     若ans = cnt - 1,则说明所有结点连接到一个根节点上,是一棵树;若不相等,则不是一棵树。

解题过程中的问题:

  1. 最初,判断是否为森林的方法是利用set,即判断集合里所有节点是否具有同一个根;判断是否有多个父节点时利用map,即输入当前有向边后,判断map中是否已存在<当前节点, 父节点>对。结果报MLE,弃用STL。
  2. 改为如上方法,用两个数组来维护每个节点的访问情况和入度情况,最后ac。

二、题解代码

 1 #include <iostream>
 2 #include "stdio.h"
 3 #include "stdlib.h"
 4 #include "string.h"
 5 #include <set>
 6 #include <map>
 7 
 8 #define MAX 500000
 9 
10 using namespace std;
11 
12 int root[MAX];
13 int num[MAX];
14 bool vi[MAX];
15 
16 void init()
17 {
18     for(int i = 0; i < MAX; i++)
19         root[i] = i;
20 }
21 
22 int find(int x)
23 {
24     if(x != root[x])
25         root[x] = find(root[x]);
26     return root[x];
27 }
28 
29 int main()
30 {
31     int count = 0;
32     int start, end;
33     int ans, cnt;
34     
35     init();
36     
37     while(scanf("%d%d", &start,&end) != EOF && (start>=0 && end>=0))
38     {
39         ++count;
40         memset(num,0,sizeof(num));
41         memset(vi,0,sizeof(vi));
42         bool flag = true;
43         ans = 0, cnt = 0;
44         if(start == 0 && end == 0)
45         {
46             printf("Case %d is a tree.\n", count);
47             continue;
48         }
49         
50         while(!(start == 0 && end == 0))
51         {
52             if(find(start) != find(end))
53             {
54                 root[end] = start;
55                 ans++;
56             }
57             else
58             {
59                 flag = false;
60             }
61             
62             if(!vi[start]){
63                 cnt++;
64                 vi[start]=1;
65             }
66             if(!vi[end]){
67                 cnt++;
68                 vi[end]=1;
69             }
70             num[end]++;
71             if(num[end] > 1)
72                 flag = false;
73             scanf("%d%d", &start,&end);
74             
75         }
76         
77         if(flag == true && ans == cnt - 1)
78             printf("Case %d is a tree.\n", count);
79         else
80             printf("Case %d is not a tree.\n", count);
81         
82         init();
83     }
84     return 0;
85 }

 

转载于:https://www.cnblogs.com/alyssayoung/p/8776875.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值