1004 Counting Leaves (30分)
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
题目大意:
给定一棵多叉树,求解每一层有多少叶子节点。然后按照层的顺序把每一层的叶子节点数进行输出。即使是0 个也输出0 。
思路分析:
树的节点编号从 0 – N-1.依然是对于多叉树的存储,我们一般是用邻接表存储。 比如之前的 1079、1090、1094、1106 这四道题,都是用对象数组进行存储。对象中包含了一个 存储孩子节点ID的 list 列表。 同样的思想,我们也可以用一个map 进行存储, key 存储父节点的ID , value 为一个list 列表,存储这个父节点的孩子节点们。 本质和邻接表是一样的。
下面的问题就转化为,在这样的一个存储模式下,如何求解每一层的叶子节点数。 其实深度优先遍历和广度优先遍历都是可以的。 这里我使用广度优先遍历,也就是层序遍历进行求解。
第一个问题是:我们如何判断一个节点是叶子节点? 它的孩纸个数为0 ,也就是map中,这个节点的key 对应的list 的size 为0 , 即孩子列表为空。
第二个问题是:如何统计每一层的叶子节点个数? 要统计每一层的叶子节点的个数,我们就必须把一层节点,放在一起处理。那么就需要我们在一个循环中把这层节点放在一起。首先我们需要知道这层节点有多少个,由于我们是在一个队列中进行计算,因此,初始时,root 节点入队,此时第1层只有一个节点。当我们在循环中处理完这一个节点,并把它的所有孩子节点入队时,下次队列中的所有节点都是第二层节点。 以此类推。
第三个问题是:我们说处理节点的时候,到底在处理什么? 其实就是判断当前从队列中取出的这个节点它是不是一个叶子节点,翻译成代码语言就是,这个节点的孩子列表是不是为空。
这次Java 可以跑过时间限制。
完整代码:
// date:3/06 score 30/30
import java.util.*;
public class P1004 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int SumNodes = input.nextInt(); // 节点个数
int Noleftnode = input.nextInt(); // 非叶子节点的个数
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
for (int i = 1; i <= SumNodes; i++) {
List<Integer> chList = new ArrayList<>();
map.put(i, chList);
}
for (int j = 0; j < Noleftnode; j++) {
int ID = input.nextInt(); // 非叶子节点的编号
int chnum = input.nextInt(); // 它有多少孩子
for (int k = 0; k < chnum; k++) {
int chilID = input.nextInt();
map.get(ID).add(chilID); // 把孩子加入map中 这个和邻接表的存储思想是一致的
}
}
//目标是求解每一层有多少叶子节点
List<Integer> res = new ArrayList<>();
Queue<Integer> queue = new LinkedList<>();
queue.offer(01);
while (queue.size() != 0) {
int nodeNum = queue.size(); // 当前层有这么多父节点
int count = 0;
// 处理一层
for (int i = 0; i < nodeNum; i++) { // 处理每一个父节点
int parId = queue.poll(); //我拿到一个父节点
List<Integer> chilist = map.get(parId); //然后我拿到该父节点的孩子列表
// 判断这个孩子列表是否为空 即这个父节点是不是叶子结点
if (chilist.size() == 0) { // 如果孩子类表是空 则 这个父节点是一个叶子结点
count++;
} else { // 如果不是空, 把它所有的孩子 都加入队列
for (int p = 0; p < chilist.size(); p++)
queue.offer(chilist.get(p));
}
}
res.add(count); // 不管是否为0 都要进行添加 因为每一层都要输出有多少叶子节点
}
// 输出最后的答案
for (int i = 0; i < res.size(); i++) {
System.out.print(res.get(i));
if (i != res.size() - 1)
System.out.print(" ");
}
}
}