题目大意:给你两个节点,前者指向后者(可以认为前者是后者的父节点),然后让你判断是否是一棵树。
解题思路:先说说这道题和小希的迷宫(HDU1272)那道题的区别,前者给出的两个点是有方向的,而后者是没有的,这就是唯一的区别。再者这道题其实就是让你判断所有的点最后所形成的图是否是一棵树。做这道题时错误了很多遍,细想之,主要是开始思路不好,很容易乱,理清思路让代码变得清晰起来就好了。判断一个图是否为一棵树。有三个重要条件(比小希的迷宫多了一个条件):
1:已经在一个集合里面的两个数不能再同时出现了(无环图)。
2:根节点只有一个(是树不是森林)。
3:除了根节点之外所有的节点的入度为一。
上面三个条件都满足了就是一颗树了,对于第一个条件,即判断是否新给的两个数的根节点是否相同。第二个条件最后统计一下根节点的数量是否小于2,(不是等于一,因为空树也是树,根节点为0~~~),第三个条件,可以观察观察数据,入度是指被指向的那个点,对于每次给定的两个数,后面那个数字出现的次数即是这个点的入度。所以可以用一个数组,利用下标代表这个点,利用值代表出现的次数。最后统计下看是否有出现次数大于一的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 3;
int pre[MAXN]; //储存父节点
bool bol[MAXN]; //这个点是否出现过
int flag1 = 1; //代表入度是否满足是一个树
int flag2 = 1; //代表是否成环。
int cnt[MAXN]; //记录出现的点的入度
int Find(int x)
{
int r = x;
while(pre[r] != r)
{
r = pre[r];
}
int i = x,j;
while(pre[i] != r)
{
j = i;
i = pre[i];
pre[j] = r;
}
return r;
}
void Mix(int a,int b)
{
int x = Find(a);
int y = Find(b);
if(x > y)
{
pre[x] = y;
}
if(x < y)
{
pre[y] = x;
}
}
int Search()
{
int cnt = 0;
for(int i = 1; i <= MAXN; i++)
{
if(bol[i])
if(pre[i] == i)
cnt++;
}
return cnt;
}
int main()
{
int M,N;
flag1 = 1; //一大堆初始化0.0
flag2 = 1;
for(int i = 1; i <= MAXN; i++)
{
pre[i] = i;
bol[i] = false;
}
memset(cnt,0,sizeof(cnt));
int kas = 1;
while(~scanf("%d%d",&M,&N)&&(M != -1 || N != -1))
{
bol[M] = true;
bol[N] = true;
cnt[N]++;
if(M != 0 && N != 0)
{
int m = Find(M);
int n = Find(N);
if(m == n)
flag2 = 0; //出现了环
Mix(M,N);
}
else
{
int single = Search(); //根节点的个数
for(int i = 1; i <= MAXN;i++)
{
if(cnt[i] > 1)
flag1 = 0; //有入度大于一的出现
}
if(single < 2 && flag1 && flag2) printf("Case %d is a tree.\n",kas++); //三个条件都满足
else printf("Case %d is not a tree.\n",kas++);
flag1 = 1;
flag2 = 1;
for(int i = 1; i <= MAXN; i++)
{
pre[i] = i;
bol[i] = false;
}
memset(cnt,0,sizeof(cnt));
}
}
return 0;
}