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");


}

转载于:https://www.cnblogs.com/doragd/p/11281829.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值