摘要
本题主要考察做题人对树这种数据结构的dfs(深度搜索)的应用,总体来说不算一道特别难的算法题。
原题
A family hierarchy is usually presented by a pedigree tree. Your job is to count those family members who have no child.
Input Specification:
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
.
The input ends with N being 0. That case must NOT be processed.
Output Specification:
For each test case, you are supposed to count those family members who have no child for 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
题目意思
现在有一棵树,树上有N个结点,其中有M个父结点,接下来M行每行第一个是父结点名称,第二个是该父节点有多少个子节点,第三个以后是其每个子结点的名称。现在要找到树的每一层有多少个叶子结点(没有子结点的结点称为叶子结点)并输出。
思路
本题首先要做的就是把题目给的数据用树保存下来,考虑到测试用例的数据会存在所给父结点乱序的情况,使用字典以"node_id:[*children]"的方式保存父结点和子结点会自动对父结点进行排序。
然后对树进行dfs深搜,每次搜索一层时如果发现某个结点在tree的键值里表示该结点是父节点,此时需要判断该结点是否被搜索过,否则可能会进入无限递归,然后对为搜索的继续递归即可。若不在tree的键值里,则将该深度的叶子结点计数+1后return即可。
测试样例
输入
8 4
01 2 02 03
02 2 04 05
04 2 07 08
03 1 06
输出
0 0 2 2
Python代码
def dfs(node, depth):
visited[node] = True # 每次搜一个结点就讲节点改成已经遍历
global max_depth
max_depth = max(max_depth, depth) # 更新最大深度
if node not in tree: # 判断当前结点是否在tree里,不在就表示是叶子结点
leave_num[depth] += 1
return
for child in tree[node]: # 如果是父结点就搜索该结点的所有子节点
if child not in visited: # 必须判断是否被搜索过,否则会导致无限递归
dfs(child, depth + 1)
# n为节点数,m为父节点数
n, m = map(int, input().split())
# 用字典存储树能自动对结点排序避免输入乱序,在tree中只保留所有有子结点的结点
tree = {}
for i in range(m):
node_id, child_num, *children = input().split() # 输入所有的父节点,子节点个数,子节点id
tree[node_id] = children # 将所有父节点保存进树中
# 记录每个深度的叶子节点数量(列表长度应为n+1因为可能出现只有左、右子树的情况)
leave_num = [0 for i in range(n + 1)]
max_depth = 0 # 最大深度决定我们最终搜索到的层数
# dfs算法搜索每层叶子结点个数
visited = {} # 记录是否遍历过某一结点
dfs('01', 0)
print(" ".join(str(i) for i in leave_num[:max_depth + 1]))