POJ 1308(并查集) (Data_Structure)
满足一下条件是树:
(1)只有一个根;
(2)一个入度为0的节点,其他节点入度都为1
第一个用并查集,第二个搞个数组统计下就OK。
我用set来存点,因为这些点在输入中可能出现多次,用set只会存一次,set方便些啦!
代码:
#include <cstdio>
#include <cstdlib>
#include <set>
#include <iterator>
#define N 10001
using namespace std;
set<int> s;
set<int>::iterator iter;
int father[N];
int degree[N];
void make_set();
int find_set(int x);
void unin(int x,int y);
int main()
{
int i,j,f,a,b,k,zero;
bool fail;
k = 1 ;
while(scanf("%d%d",&a,&b) && (a!= -1 && b != -1))
{
/*
空树也是树
*/
if( a == 0 && b == 0)
{
printf("Case %d is a tree.\n",k++);
continue;
}
/*
每组数据都得清空 set容器
*/
s.clear();
s.insert(a);
s.insert(b);
/*
初始化
*/
make_set();
unin(a,b);
++degree[b];
while(scanf("%d%d",&a,&b) && (a&&b))
{
s.insert(a);
s.insert(b);
unin(a,b);
++degree[b];
}
f = find_set(father[*s.begin()]);
zero = 0 ;//统计有几个入度为 0 的点
fail = false;
for( iter = s.begin(); iter != s.end(); ++iter)
{
/*
树的每个点的祖先都一样,否则不是树
*/
if(f != find_set(father[*iter]))
{
fail = true;
break;
}
/*
树不能有入度大于 1的节点,否则不是树
*/
if(degree[*iter]>1)
{
fail = true;
break;
}
else
{
/*
统计根
*/
if(degree[*iter] == 0)
++zero;
}
}
printf("Case %d ",k++);
if(fail || zero != 1)
{
printf("is not a tree.\n");
}
else
printf("is a tree.\n");
}
return 0;
}
void make_set()
{
int i;
for(i= 1; i < N; ++i)
{
father[i] = i;
degree[i] = 0;
}
}
int find_set(int x)
{
int t;
if(x != father[x])
father[x] = find_set(father[x]);//路径压缩
return father[x];
}
/*
因为是树,合并是有方向的
*/
void unin(int x,int y)
{
x = find_set(x);
y = find_set(y);
father[y] = x;
}

浙公网安备 33010602011771号