poj1308 Is It A Tree

链接: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;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值