链接:http://poj.org/problem?id=1308
题意:给一个图,判断是不是树。题目中给的判断条件是:
1.There is exactly one node, called the root, to which no directed edges point.
2.Every node except the root has exactly one edge pointing to it.
3.There is a unique sequence of directed edges from the root to each node.
1.只有一个树根,并且入度为零;
2.除了树根,每个点的入度必为1;
3.对于每个点,从树根到这个点只有唯一的一条路;
除此之外,对于一些特殊的数据要做一些处理:
1: 0 0 空树是一棵树
2: 1 1 0 0 不是树 不能自己指向自己
3: 1 2 1 2 0 0 不是树
4: 1 2 2 3 4 5 0 0不是树 森林不算是树
5: 1 2 2 3 3 2 0 0 注意 一个节点在指向自己的父亲或祖先 都是错误的 即 3-->2 错误
我采用的方法主要是借用图的知识来做。设置一个map数组构图。详见代码。
#include<stdio.h>
#include<string.h>
#define MAXN 1000 //这个题的数据量未知,所以随便设了1000,据说15都能过。。。
int map[MAXN][MAXN];//map数组用来构图
int into[MAXN],vist[MAXN];//into数组记录每个点的入度,vist数组记录某个点是否出现,因为点序号不连续
int MIN(int a,int b,int c)
{
int temp1,temp2;
temp1=a>b?b:a;
temp2=temp1>c?c:temp1;
return temp2;
}
int MAX(int a,int b,int c)
{
int temp1,temp2;
temp1=a<b?b:a;
temp2=temp1<c?c:temp1;
return temp2;
}
int main()
{
int i,j;
int num,flag1,flag2,test=1;
int s,e;
int min,max; //min、max分别记录最小序号和最大序号,用于减少遍历的时间
memset(map,0,sizeof(map));//初始化
memset(into,0,sizeof(into));
memset(vist,0,sizeof(vist));
min=MAXN+1;
max=0;
flag1=0;
flag2=0;
num=0;
while(scanf("%d%d",&s,&e)!=EOF)
{
if(s==-1&&e==-1)//-1 -1程序结束
break;
if(!s&&!e) // 0 0,开始对数据进行处理
{
if(min==MAXN+1&&max==0) //处理空树(0,0)
printf("Case %d is a tree.\n",test++);
else
{
for(i=min;i<=max;i++)
{
if(flag1)
break;
for(j=min;j<=max;j++)
if(map[i][j]) //求点的连通入度,如果i、j
{
vist[i]=1; //记录出现的点的序号
vist[j]=1;
into[j]++;
if(into[j]>=2) //入度只能为1,大于2不符合题意
{
flag1=1;
break;
}
}
}
for(i=min;i<=max;i++)
if(vist[i]&&!into[i]) //求根的数量;如果num>1,则为森林;如果num=0,则无根,不符合题意
num++;
if(num>1||!num)
flag2=1;
if(!flag1&&!flag2)
printf("Case %d is a tree.\n",test++);
else
printf("Case %d is not a tree.\n",test++);
}
memset(map,0,sizeof(map));
memset(into,0,sizeof(into));
memset(vist,0,sizeof(vist));
min=MAXN+1;
max=0;
flag1=0;
flag2=0;
num=0;
}
else
{
min=MIN(min,s,e);
max=MAX(max,s,e);
if(map[s][e]) //如果map[s][e]==1,则s、e已经连通,避免重复
flag1=1;
else map[s][e]=1;
}
}
return 0;
}