PAT 甲级1004 Counting Leaves
N为树中节点数量0 < N < 100,M为叶子节点数量。
ID是代表非叶子节点的两位数(有child),K是其儿子节点数量, 后跟k个儿子节点ID
要按层输出每层叶子节点的数量
就是对树进行搜索
-
深度优先搜索DFS
按深度优先对树进行搜索,每当遇到一个节点,如果该节点是叶子节点,则将该层的叶子节点数量++,同时比较该层深度与已知最大深度,如果该层深度更深,更新最大深度。
如果该节点不是叶子节点,则对该节点的每个叶子节点,递归调用本函数。这样从根节点出发,将一直向更深处搜索,直到遇到一个叶子节点,此时返回该叶子节点的父节点,搜索该父节点的下一个儿子节点,如果没有下一个儿子节点,则继续返回。
这个算法在什么时候结束呢?在遍历完根节点的所有儿子节点后(或者该根节点本身就是叶子节点)
res< int> res[100]保存N个向量,res[i]保存节点i的儿子节点的信息
book[100]:book[i]记录第i层的叶子节点数,因为0 < N < 100,所以该树必定小于100层。
// 1004 Counting Leaves.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <vector> using namespace std; vector<int> res[100]; int book[100], maxdepth = -1; void dfs(int index, int depth) { if (res[index].size() == 0) { book[depth]++; maxdepth = max(depth, maxdepth); return; } else { for (int i = 0; i < res[index].size(); i++) { dfs(res[index][i], depth + 1); } } } int main() { int n, m, node, k, c; cin >> n >> m; for (int i = 0; i < m; i++) { cin >> node >> k; for (int j = 0; j < k; j++) { cin >> c; res[node].push_back(c); } } dfs(1, 0); for (int i = 0; i <= maxdepth; i++) { if (i != 0) cout << " "; cout << book[i]; } return 0; }
-
广度优先搜索
层序遍历,首先将根节点加入队列,然后只要队列不为空就进行循环,每次取出队首节点,如果该节点无儿子节点,对应book[depth]++,如果有儿子节点,则将其儿子节点逐个加入队列中,记录此时队列中最后一个元素。当取出的元素等于记录的最后一个元素时,说明一层遍历完,进入下一层,更新最后一个元素的记录。
void bfs(int index, int depth) {
int root = index;
q.push(root);
while (q.size()) {
int v = q.front(), p = -1;
q.pop();
if (res[v].size() == 0) {
book[depth]++;
maxdepth = max(depth, maxdepth);
}
else {
for (int i = 0; i < res[v].size(); i++) {
q.push(res[v][i]);
p = res[v][i];
}
}
if (v == root) {
depth++;
root = p;
}
}
}
这种写法的bfs无法通过测试点2,麻了,还想不明白为啥
更新,给一个输入用例说明:
12
5
01 3 02 03 04
02 2 05 06
03 2 07 08
05 2 09 10
06 2 11 12
问题在于变量p定义在循环之内,当v指向3时,将3的儿子节点7、8加入队列,此时p更新为8,然后继续循环,v指向4,**此时p被循环内赋值为-1,**可知4是第二层的最后一个节点,此时应该进入:
if (v == root) {
depth++;
root = p;
}
的循环中,可以知道,虽然进入了下一层,但root被赋值为-1,而不是我们想要的下一层的最末一个节点8(它被覆盖了)。
所以当我们进入第三层时,当v最终指向8时,因为root为-1,并不能进入上面这个循环,层数无法递增,所以depth保持在第三层的情况下,我们继续遍历队列中剩余的几个第四层节点,对它的叶子节点计数加到了第三层上。
book[depth]++;//depth = 3
因此最后的输出为
0 1 6
而不是
0 1 2 4
更正这种写法:
void bfs1(int index, int depth) {
int root = index;
q.push(root);
int p = -1;
while (q.size()) {
int v = q.front();
q.pop();
if (res[v].size() == 0) {
book[depth]++;
maxdepth = max(depth, maxdepth);
}
else {
for (int i = 0; i < res[v].size(); i++) {
q.push(res[v][i]);
p = res[v][i];
}
}
if (v == root) {
depth++;
root = p;
}
}
}
另一种写法,参考尹神,以后bfs都按照这种写法,比较好理解
void bfs(int index, int depth) {
int root = index;
q.push(root);
q.push(-1);
while (q.size()) {
if (q.front() == -1) {
q.pop();
depth++;
if (!q.empty()) q.push(-1);
}
else {
int v = q.front();
q.pop();
if (res[v].size() == 0) {
book[depth]++;
maxdepth = max(depth, maxdepth);
}
else {
for (int i = 0; i < res[v].size(); i++) {
q.push(res[v][i]);
}
}
}
}
}
向队列中插入-1作为一行的终结符,如果取出的队首元素为-1且队列空,则说明取完了,不要再插入-1,否则就再插入-1作为下一行的终结符。
可通过测试点2,以后我想明白为啥再来更新。