http://poj.org/problem?id=1308
思路:并查集,判断是否是一颗树。
分析:如果是一颗树,那么肯定只有一个根节点。自己想的时候不知道怎么判断是否只有一个根节点,看了别人的题解才知道。在输入的时候判断两个节点能否合并,能的话合并。需要注意的是,在输入的时候如果两个点的根节点相同,那么肯定不是一棵树,可以自己画图看一下。输入完了之后判断是否所有的节点都具有相同的根节点。 !!!另外,这道题的坑比较多,需要注意的是”空树“也是一棵树,”森林“不是树。
注意一下数据(仍然不是自己想出来的):
- 0 0 是空树,也是树,符合题意。
- 1 1 0 0 不是树,其实是个自环,不合题意。
- 1 2 1 2 0 0 这种情况自己不是很懂,不过好像是因为两个根节点相同(没理解)。
- 1 2 2 3 4 5 0 0 是森林,不是树。
- 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 1不是树,最后9和1的根节点相同,所以不是。
- 1 2 2 1 0 0 不是树。
代码:
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vector>
#include <string.h>
#include <string>
#include <algorithm>
#include <set>
#include <map>
#include <cstdio>
#include <iterator>
using namespace std;
const int maxn = 1000000 + 10;
int fat[maxn];
set<int> s;
//每次写并查集,都会忘掉初始化。!!!不能再忘了!!!
void init()
{
s.clear();
for(int i = 0;i <= maxn;i++)
{
fat[i] = i;
}
}
//查找父节点
int fin(int x)
{
if(x == fat[x])
return x;
int y = fin(fat[x]);
return fat[x] = y;
}
int main()
{
int x,y;
int cas = 0;
while(scanf("%d%d",&x,&y) && x >= 0)
{
printf("Case %d ",++cas);
if(x + y == 0)
{
puts("is a tree.");
}
else
{
init();
s.insert(x);
s.insert(y);
fat[y] = x;
bool isok = (x == y ? false : true);
while(scanf("%d%d",&x,&y) && x && y)
{
s.insert(x);
s.insert(y);
int fx = fin(x);//第一次直接判断的x,y是否相等,行不通
int fy = fin(y);//x==y是自环,不是树,两者的父节点相同也不是树
if(fx == fy)//如果输入的两个数有相同的父节点,就肯定不是一颗树
{
isok = false;
}
else
{
fat[fy] = fx;
}
}
if(!isok)
{
puts("is not a tree.");
}
else
{
set<int>::iterator it = s.begin();
int root = fin(*it);//这里是先用一个找到根节点,接下来入股其他所有节点的根节点都是这一个,说明是树,否则不是树。
for(it++;it != s.end();it++)
{
if(root != fin(*it))
{
isok = false;
break;
}
}
if(!isok)
{
puts("is not a tree.");
}
else
{
puts("is a tree.");
}
}
}
}
return 0;
}
还有点儿基础的知识点没搞明白,自己真的垃圾,想做acm,连这么基础的东西都不清楚,也是没谁了。
puts函数输出字符串会自动添加换行,相当于printf(“%s\n”,s);。