[PAT解题报告] Counting Leaves
给定一个树,求每层没有孩子的节点数。首先,树是邻接表的形式给的,即每个节点的孩子有哪些。其次,这个树是有根树。注意:节点数0
< N < 100, 但题目好像没说节点id是连续的,尽管都小于100。所以我没有假设节点id连续,读入的节点数n,我也没有用。
不过我假设了每个写出的节点id, k 后面跟k个孩子,而k不应该等于0,确实题目没说k != 0这个问题……
两种办法解决这个问题:
第一种方法对每个节点记录一个父亲f值,然后标记该节点是否有孩子hasSon[i]——我们不应该用度是否为1来判断叶子,因为只有两个节点的时候,根不能算做叶子。然后根据f值计算每个节点的深度dep,
一般dep[i] = dep[f[i]] + 1,
这个可以dfs出来。我还记录了每个编号的节点是否存在mark[],有了这些信息之后,如果节点i深度为
i并且没有孩子,我们就把它的深度加到最终答案上就好了,++a[dep[i]]。当然还要记录树的高度max{dep[i]},最后输出就行了。这个做法有个细节,当n
= 1, m =
0时,这个树是个孤立点,我们根据读入的信息,无法记录mark值,也就是说我们会认为这个树没有节点,这种情况应该输出1——记得要特判一下,有点不美观。
代码:
#include <cstdio> #include <cstring> #include <string> #include <cstdlib> using namespace std; const int N = 102; bool mark[N]; int dep[N]; int f[N]; bool haveSon[N]; int a[N]; int getDep(int x) { return ((!mark[x]) || (f[x] < 0))?0:(1 + getDep(f[x])); } int main() { int n, m; scanf("%d%d",&n,&m); if (m == 0) { puts("1"); return 0; } for (memset(f, 0xff, sizeof(f));m;--m) { int x,y; for (scanf("%d%d",&x,&y);y;--y) { int z; scanf("%d",&z); mark[z] = true; f[z] = x; } mark[x] = haveSon[x] = true; } n = 0; for (int i = 0; i < N; ++i) { if (mark[i]) { dep[i] = getDep(i); if (!haveSon[i]) { ++a[dep[i]]; } n = max(n, dep[i]); } } for (int i = 0; i <= n; ++i) { if (i) { putchar(' '); } printf("%d",a[i]); } puts(""); return 0; }
第二种方法是稍微麻烦一点,我们同样用mark[]记录节点是否出现,并且用canRoot[]表示这个节点是否可能是根(没有父亲)。根据读入的信息,我们更新mark,
canRoot——这和前面差不多,并且我们用vector<int>
son[]存放每个节点的孩子们,也就是读进来直接扔到vector里面去。然后,我们找到树根也就是canRoot[r] == true
&& mark[r] == true的点——如果找不到r = 0,这就是我说的n = 1, m =
0的特殊情况。接下来我们对树从根开始做层序遍历,也就是bfs。bfs时用两个队列来回折腾的方法——先从一个队列1出队,把那些孩子全放入队列2。队列1清空后,从队列2出队,把孩子放入队列1……这样每个队列负责一层,而且只有两个队列。实现这个的方法我们用两个变量表示队列编号就好了。比如last
= 0, now = 1 ^ last。每次循环后last ^= 1就好了,实际上last就是0,1,0,1,0,1这样的,now正好是1
- last。我们遍历完一层就能统计没有孩子的节点数了,因为没有孩子的节点son[x].empty() == true。
代码:
#include <cstdio> #include <string> #include <cstring> #include <queue> using namespace std; const int N = 102; bool canRoot[N]; bool mark[N]; vector<int> son[N]; queue<int> q[2]; int main() { int n, m; for (int i = 0; i < N; ++i) { canRoot[i] = true; } for (scanf("%d%d",&n,&m);m;--m) { int x,y; for (scanf("%d%d",&x,&y);y;--y) { int z; scanf("%d",&z); mark[z] = true; canRoot[z] = false; son[x].push_back(z); } mark[x] = true; } int r = 0; for (int i = 0; i < N; ++i) { if (mark[i] && canRoot[i]) { r = i; break; } } q[0].push(r); bool first = true; for (int last = 0;!q[last].empty();last ^= 1) { int answer = 0; int now = last ^ 1; while (!q[last].empty()) { int x = q[last].front(); q[last].pop(); if (son[x].empty()) { ++answer; } else { for (int i = 0; i < son[x].size(); ++i) { q[now].push(son[x][i]); } } } if (first) { first = false; } else { putchar(' '); } printf("%d",answer); } puts(""); return 0; }题目链接: http://www.patest.cn/contests/pat-a-practise/1004