PAT A1004 Counting Leaves [树的DFS,BFS]
题目描述
链接
给出一棵树,问每一层各有多少个叶子结点
分析
建树
- 使用树的静态写法
- 下标为结点地址
struct node{
int data; //当这个结点有点权时
vector<int> child; //保存孩子的下标
}nodes[maxn];
- 这里题目只是用到了结点的编号,没有点权,所以变成
vector<int> v[maxn]; //注意结点编号从1开始还是0!!
BFS解法
很自然可以想到用BFS遍历树,对于一个结点,如果没有孩子\(child.size()==0\) 则说明是叶子,那么当层的\(ans[layer]++\)
但是一开始无脑套模板就错了。关键没搞清楚BFS在干啥。
错误写法:
int layer;
void bfs(){
queue<int> q; //注意push的是结点编号,不是node
q.push(1);
while(!q.empty()){
int i = q.front();
q.pop();
if(!nodes[i].child.size()) ans[layer]++;
for(int j=0;j<nodes[i].child.size();j++){
q.push(nodes[i].child[j]);
}
layer++;
}
}
其实BFS按照上面这么写的话,就会造成取出该层第一个结点进行判断后,layer++了,然后再取出该层第2个结点。所以应该把该层所有结点判断完,再layer++。
void bfs(){
queue<int> q;
q.push(1);
while(!q.empty()){
int len = q.size(); //因为后面pop会改变,所以提前存好。然后实际上后续push入队的结点不会影响该层的结点,因为队列的特性入队是在最后,同时len已经确定好了。所以不会影响。
for(int i=0;i<len;i++){ //该层所有结点
int id = q.front();
q.pop();
if(v[id].size() == 0) ans[layer]++;
for(int j=0;j<v[id].size();j++){
q.push(v[id][j]);
}
}
layer++; //当前层所有结点判断好了,再layer++
}
}
实质上,纯粹的bfs模板也可以改成下面,本质一样的,因为入队在最后,所以push不会影响原来的
void bfs(){
queue<int> q;
q.push(1);
while(!q.empty()){
int len = q.size();
for(int i=0;i<len;i++){
int now = q.front();
q.pop();
for(int j=0;j<nodes[i].child.size();j++){
q.push(nodes[i].child[j]);
}
}
}
}
DFS解法
- 每调用一次,\(depth++\),用这个来表示层数,\(dfs\)到叶子时,\(ans[depth]++\)
int depth;
void dfs(int root){
depth++;
if(v[root].size() == 0){
ans[depth]++;
maxdepth = max(maxdepth, depth);
depth--; //不要忘记这里也要回溯
return;
}
for(int i=0;i<v[root].size();i++){
dfs(v[root][i]);
}
depth--;
}
int depth;
int maxdepth;
void dfs(int root, int depth){ //如果把depth当成一个状态参数就不用回溯了,其实这是我最初的想法,想每个结点都有个depth,但是放在哪呢?变成一个结构体?不对,应该放在dfs状态里面。
if(v[root].size() == 0){
ans[depth]++;
maxdepth = max(maxdepth, depth);
return;
}
for(int i=0;i<v[root].size();i++){
dfs(v[root][i], depth+1);
}
}
完整代码
#include<bits/stdc++.h>
using namespace std;
vector<int> v[105];
int n,m,k,t,id,layer;
int ans[105];
int depth;
int maxdepth;
void dfs(int root){
depth++;
if(v[root].size() == 0){
ans[depth]++;
maxdepth = max(maxdepth, depth);
depth--;
return;
}
for(int i=0;i<v[root].size();i++){
dfs(v[root][i]);
}
depth--;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d",&id,&k);
for(int i=0;i<k;i++){
scanf("%d",&t);
v[id].push_back(t);
}
}
dfs(1);
for(int i=1;i<=maxdepth;i++){
if(i==1) printf("%d",ans[i]);
else printf(" %d",ans[i]);
}
printf("\n");
}