zoukankan      html  css  js  c++  java
  • 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("
    ");
    
    
    }
    
    
  • 相关阅读:
    我给老师发的邮件
    [LeetCode]Sum Root to Leaf Numbers
    [LeetCode]Binary Tree Inorder Traversal
    [LeetCode]Merge Sorted Array
    [LeetCode]Unique Paths II
    [LeetCode]Unique Paths
    [LeetCode]Sort Colors
    [LeetCode]Balanced Binary Tree
    [LeetCode]Valid Palindrome
    [LeetCode]Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/doragd/p/11281829.html
Copyright © 2011-2022 走看看