题意:给出一个有向图,判断是否为一棵树。
题目链接:http://poj.org/problem?id=1308
——>>看到这题,觉得好爽啊,每个点的入度不超过1,顶点数==边数+1,是不是就OK了?于是立马写了一个,到hdu - 1325一交,AC了,于是复制到训练的专题上再交,WA!My God,这是什么情况???接着到HUST上找了一下,poj - 1308与Uva - 615上也有,submit上去碰碰运气,结果两个OJ都是返回WA,不得不承认,我的算法错了……
改了一阵,最后用并查集过掉:
1、 每个点的入度不超过1
2、 无环(并查集时当无向图来做即可)
3、 一棵树(最后对maxn个点扫描,如果该点用过且是树根,计数器+1)
代码如下:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1000 + 10; //题意没说多少个点,经测试,1010个点已可以
int in_de[maxn], fa[maxn]; //in_de[i]为顶点i的入度
bool vis[maxn]; //vis[i]记录点i是否被访问过
int find_set(int x) //带路径压缩的并查集查找函数
{
if(x == fa[x]) return x;
else return fa[x] = find_set(fa[x]);
}
int union_set(int x, int y) //并查集合并函数
{
int root_x = find_set(x);
int root_y = find_set(y);
if(root_x == root_y) return 0;
else fa[root_y] = root_x;
return 1;
}
int main()
{
int u, v, cnt = 1, i; //cnt为测试数据组数
bool ok = 1; //是否为树的标记
memset(in_de, 0, sizeof(in_de)); //初始化
memset(vis, 0, sizeof(vis)); //初始化
for(i = 0; i < maxn; i++) fa[i] = i; //初始化
while(cin>>u>>v)
{
if(u == -1 && v == -1) return 0;
if(!u && !v)
{
int cset = 0; //计数多少个树根
for(i = 0; i < maxn; i++)
{
if(vis[i] && fa[i] == i && (++cset > 1))
{
ok = 0;
break;
}
}
if(ok) cout<<"Case "<<cnt++<<" is a tree."<<endl;
else cout<<"Case "<<cnt++<<" is not a tree."<<endl;
ok = 1; //重新初始化
memset(in_de, 0, sizeof(in_de));
memset(vis, 0, sizeof(vis));
for(i = 0; i < maxn; i++) fa[i] = i;
}
else
{
if(++in_de[v] > 1 || !union_set(u, v)) ok = 0; //入度超过1,存在环时
if(!vis[u]) vis[u] = 1; //记录访问点
if(!vis[v]) vis[v] = 1; //记录访问点
}
}
return 0;
}