题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1325
解析:
首先,我不得不吐槽一下,这题又是一个没有数据范围的题目,尼玛啊,只能慢慢地去尝试。
然后,我想说一下这个题目真的考虑的问题很多,是一个难度较高的并查集问题。
并查集在这里就不多说了,就谈一谈怎么去去判断吧!这里我们要判断是否是一棵树树,那么就不能出现环和森林。另外,这里的树枝是有方向的,所以每个点的入度不能大于1。
但是,我这里还存在着一个疑问,当我将判断入度的表达式放在判断是否是一棵树的循环里的时候,给的答案是WA的,但是当我把他在并查语句后面判断的时候就是正确的,有没有人能够解释一下这其中的问题呢?
在这里给出几个坑爹的数据
//数据:
0 0
1 1 0 0
1 2 2 1 0 0
1 2 2 3 3 4 4 1 0 0
1 2 2 3 3 1 5 6 0 0
1 2 2 3 4 3 0 0
1 2 2 3 5 6 0 0
2 3 0 0
//答案:
Case 1 is a tree.
Case 2 is a tree.
Case 3 is not a tree.//环
Case 4 is not a tree.//环
Case 5 is not a tree.
Case 6 is not a tree.//节点3入度大于1
Case 7 is not a tree.//两棵树
Case 8 is a tree.
代码:
/*
ID:muller8
Name: 1325 Is It A Tree?
Reference: 并查集
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <vector>
using namespace std;
#define MAXN 100010
#define INF 1e9
int fa[MAXN];
int in[MAXN];
bool visit[MAXN];
vector<int> vec; //保存所有的节点
void init(){
memset(in,0,sizeof(in));
memset(visit,false,sizeof(visit));
vec.clear();
for(int i=0;i<MAXN; ++i)
fa[i] = i;
}
int find(int n){
if(fa[n]!=n)
fa[n] = find(fa[n]);
return fa[n];
}
int main(){
int x,y;
bool flag = true;
int Case = 0;
init();
while(~scanf("%d%d", &x,&y)){
if(x<0&&y<0) break;
if(0==x&&0==y){
if(flag){
if(vec.size()){
int tmp = find(vec[0]);
for(int i=1; i<vec.size(); ++i) //判断是否只有一棵树
if(tmp!=find(vec[i])){
flag = false;
break;
}
}
}
printf("Case %d is %s\n", ++Case, flag?"a tree.":"not a tree.");
flag = true;
init();
continue;
}
//用一个vector来保存所有出现过的节点
if(!visit[x]){
visit[x] = true;
vec.push_back(x);
}
if(!visit[y]){
visit[y] = true;
vec.push_back(y);
}
if(!flag) continue; //如果已经不是一棵树了,也就不必要太多的操作
if(x==y) continue; //如果是同一个点也不用进行运算,当然这里是防止坑爹数据的
int fx, fy;
fx = find(x);
fy = find(y);
if(fx == fy){
flag = false;
continue;
}
else{
fa[fx] = fy;
in[y]++;
}
if(in[y]>1) flag = false; //入度大于1,flag为否
}
return 0;
}
在这里给出几个坑爹的数据