pat1004

19 篇文章 0 订阅

1004. Counting Leaves (30)

时间限制    400 ms    内存限制   32000 kB   代码长度限制    16000 B    判题程序    Standard      作者    CHEN, Yue


A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.

Input

Each input file contains one test case. Each case starts with a line containing 0 < N < 100, the number of nodes in a tree, and M (< N), the number of non-leaf nodes. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]
where ID is a two-digit number representing a given non-leaf node, K is the number of its children, followed by a sequence of two-digit ID's of its children. For the sake of simplicity, let us fix the root ID to be 01.

Output

For each test case, you are supposed to count those family members who have no childfor every seniority level starting from the root. The numbers must be printed in a line, separated by a space, and there must be no extra space at the end of each line.

The sample case represents a tree with only 2 nodes, where 01 is the root and 02 is its only child. Hence on the root 01 level, there is 0 leaf node; and on the next level, there is 1 leaf node. Then we should output "0 1" in a line.

Sample Input
2 1
01 1 02
Sample Output
0 1


题目要求:给你一个多叉树,并且不是完全的多叉树(即树中的每个节点上可以有0 到多个孩子),希望你能够统计出树中每一层上没有孩子的顶点数目。

并从根到最后一层的顺序,依次输出每一层上统计出的数目总和。


输入格式说明

仅有一个测试用例,在开始的地方N M 两个数值的含义分别代表的是,树中一共有N 个顶点,和M 个非叶子顶点,非叶子顶点说明的是后续的输入数据中,

每一行都会对非叶子顶点的孩子顶点进行数据描述,可以推知,后续接收数据的行数为 M 行, 用M 来控制接收数据的循环即可。


接下来的M行数据中的某一行数据格式如下


ID K ID[1] ....ID [K]

其中ID代表的是当前这一行中,顶点编号为 ID的树中节点一共有 K 个孩子顶点, 并且这K 个孩子顶点的编号描述如后面的 ID[1] -> ID[K] 所示。

在这里说明一下,题中已经明确的规定,顶点ID = 01 所表示的是根顶点。 并且对于字符串格式的 01 使用十进制 %d 的接收格式会被转换成 1 ,

题中同样也说明了,ID是一个 2digit  即两位数,所以在接收数据的时候直接使用十进制整数的接收方式,来替代字符串的接收方式。



输出格式要求

输出格式是,假定树的层数为 lev 那么将树根开始的第 1 层上没有孩子的节点数目总和 -> 层数 = lev 的没有孩子顶点数目的总和输出,

并且最后一个数据后面不允许有空格。


第一次采取的方法是通过构造一个数组代替树形结构,然后对树中的每一层进行遍历,统计满足题意的顶点数目。

但是代码提交后有两个地方有问题,暂时还没有好的解决方案,先将代码备份一下

#include <cstdio>
#include <cstdlib>
#include <string.h>

int N , M ;
int cur , maxLevel ;


struct node
{
	char ID[3] ;
	int level ,childNum;

	node () :childNum(0)
	{
		memset ( ID , 0 , sizeof ( ID ) ) ;
	}
	node ( char id[] ) : childNum(0)
	{
		strcpy(ID , id ) ;
	}
} ;

node tree[101 ] ;

void inPut ()
{
	char id[3] , childId[3] ;
	int K , loc  ;

	strcpy(tree[0].ID,"01\0") ; 
	tree[0].level = 1 ;
	maxLevel = 1 ;
	cur = 1 ;

	scanf("%d%d",&N,&M) ;



	for ( int i = 0 ; i < M ; i++ )
	{
		scanf("%s", id ) ;
		scanf("%d", &K ) ;

		for ( int j = 0 ; j < N ; j++ )
		{
			if ( strcmp(tree[j].ID , id )== 0 )
			{
				loc = j ;
				break ;
			}
		}

		tree[loc].childNum = K ;

		for ( int j = cur ; j < cur+K ; j++ )
		{
			scanf("%s", tree[j].ID) ;

			tree[j].level = tree[loc].level+1 ;

			if ( tree[j].level > maxLevel )
			{
				maxLevel = tree[j].level ;
			}

		}

		cur += K ;
	}
}

int countLeaves( int lev )
{
	int sum = 0 ;

	for ( int i = 0 ; i < N ; i++ )
	{
		if ( tree[i].childNum== 0 && tree[i].level == lev )
		{
			sum++ ;
		}
	}

	return sum ;
}

int main ( void )
{
	inPut() ;

	for ( int i = 1 ; i <= maxLevel ; i++ )
	{
		printf("%d",countLeaves(i)) ;
		if ( i != maxLevel )
		printf(" ") ;
	}

	system("pause") ;
	return 0 ;
}

这个可以通过dfs 搜索的方式来求解,下面是基于邻接矩阵的dfs 搜索实现的正确代码


#include <cstdio>
#include <string.h>

const int maxn = 101 ;
int tree[maxn][maxn] ;
int N , M , K;
int maxLev = -1 ;

void input ()
{
	int n ,t  ;

	scanf("%d%d", &N , &M ) ;

	memset( tree, 0 , sizeof (tree) ) ;

	for ( int i = 0 ; i < M ; i++ )
	{
		scanf("%d%d",&n,&K) ;
		
		tree[n][0] = 1 ;

		for ( int j = 1 ; j <= K ; j++ )
		{
			scanf("%d",&t) ;
			//printf("%d  ", t ) ;
			tree[n][t] = 1 ;
		}
	}
}

void dfs ( int n , int level )
{
//	printf("node %d  level %d \n", n , level) ;
	if ( maxLev < level )
	{
		maxLev = level ;
	}

	if ( tree[n][0] == 0 )
	{
		tree[0][level]++ ;
	}
	else
	{
		for ( int i = n+1 ; i <= N ; i++ )
		{
			if ( tree[n][i] != 0 )
			{
				dfs( i , level+1 ) ;
			}
		}
	}
}

void show ()
{
	for ( int i = 0 ; i <= N ; i++ )
	{
		for ( int j = 0 ; j <= N ; j++ )
		{
			printf("%d ",tree[i][j]) ;
		}

		printf("\n") ;
	}
}

int main ( void )
{
	input() ;
	//show() ;

	dfs( 1, 1 ) ;

	for ( int i = 1 ; i <= maxLev ; i++ )
	{
		printf("%d",tree[0][i]) ;
		if ( i != maxLev )
			printf(" ") ;
	}
	
//	system("pause") ;

	return 0 ;
}


上述代码的解题思路是这样的:

创建一个 二维数组  tree[101][101] , 其中 101 是树中节点数目的一个上限,101 也就是顶点数目的最大值。


将tree[1..N][0] 用来存放 N个顶点是否右孩子,

如果顶点 i 有孩子、是非叶子节点的话,那么 tree[i][0] = 1  ;否则的话 tree[i][0] = 0


然后读入数值,如果顶点 j 是定点 i 的子节点的话,那么必然有 tree[i][j] = 1 。


反之 如果 tree[i][j] = 0 那么则说明顶点 i 和顶点 j 之间没有父子关系。


这里使用表示图的邻接矩阵来表示树中顶点之间的关系是因为树实质上也是一种特殊的图
那么树上顶点之间的父子关系,就是图中两个顶点之间相互邻接关系的一种特殊情况。


然后设定树的层数为 lev ; lev 必定是要小于 N值的,这个通过二叉树的 层数 = log 树中节点数目< 树中的节点数目。

上面公式的log 是以2为底表示的是每个顶点最多有2 个孩子, 而在本题中每一个顶点的孩子有可能 > 2 所以,可以推知

树中的顶点数目一定是大于树的层次数目的。(树中顶点数 n =1 的时候, 树的层数 = 树中顶点数目 )


所以我们将每一层的没有孩子的节点数目总和记录在 tree[0][lev] 中, lev <= N .


即如果当前层数为 x 的话,并且该x层中的无孩子的节点数目之和为 y 的话,那么 tree[0][x] = y


然后通过dfs 深度优先搜索的方法来对树中的每一层顶点进行遍历 , dfs 的算法思想如下:


设定最大的层次数目为 maxLev = -1 ; //为了方便更新,将其数值设定为负值


dfs ( currentNode , currentLevel )
{

如果当前层次数目 > maxLev 
maxLev <- 当前层次数目


1.如果 tree[currentNode][0] == 0 

tree [0] [ currentLevel]++ ;

所表明的是当前节点 currentNode没有孩子,
并且已知当前节点所在树中的第 currentLevel 层)
则 tree[0][currentLevel]++ ; //将当前所在树中的层次上的没有孩子节点的数目增加 1

)


2. 如果 tree[currentNode][0] != 0 

{

for ( i = currentNode+1 ; i <= N ; i++ )

{

if ( tree[currentNode][i] ! = 0 )

{

dfs( i , currentLevel+1 ) ;

}

}

}

所表明的是当前节点 currentNode 有孩子,所以通过dfs 的方式来遍历当前节点 currentNode 的孩子,

由于currentNode 与它的孩子必定不是在同一层上,并且一定是下一层所以在遍历当前顶点孩子的时候,需要将层次增加 1。

同时,由于题目中的顶点顺序必定是以从 01 -> N 的方式增加的,那么顶点currentNode 的孩子顶点编号一定 > currentNode,

所以判定程序的起始顶点标号为 currentNode+1 .

 )

这样在所有的dfs 递归返回之后,tree的[0][1..maxLev] 的数值即为 从 第1层 到第 maxLev层上所有没有孩子顶点数目记录的总和

}//dfs



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值