• 树和图的深度优先搜索的模板框架


    #include<iostream>
    
    using namespace std;
    
    int N = 1e5 + 10,M = N*2;
    
    //h表示链表头,e存储的是所有的边,ne表示所有的next指针是多少,相当与n个单链表
    int h[N],e[M],ne[M],idx;
    
    //深度优先搜索和宽度优先搜索每个点只会遍历一次
    bool st[N];//存一下那些点已经被遍历过了,就不要再遍历他了
    
    void add(int a,int b){//a前插入b
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    //树和图的深度优先搜索的代码 时间复杂度是O(n + m),因为点数和边数呈线性关系
    //u表示已经遍历到这个节点了
    int dfs(int u){
        st[u] = true;//首先先标记下当前这个点已经被搜索过了
        
        //遍历下u的所有的初边
        for(int i = h[u];i != -1;i = ne[i]){
            // 存储当前结点对应图里边结点的编号是多少
            int j = e[i];
            //如果当前点没有做过的话,就一直搜,一条路走到黑
            if(!st[j]) dfs(j);
            
        }
    }
    
    int main(){
        //头结点指向-1,n给单链表的头结点指向-1
        memset(h,-1,sizeof h);
        
        dfs(1);//从第一个点开始搜索
    }
    

      例题:

    846. 树的重心

    给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。

    请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。

    重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

    输入格式

    第一行包含整数n,表示树的结点数。

    接下来n-1行,每行包含两个整数a和b,表示点a和点b之间存在一条边。

    输出格式

    输出一个整数m,表示重心的所有的子树中最大的子树的结点数目。

    数据范围

    1n1051≤n≤105

    输入样例

    9
    1 2
    1 7
    1 4
    2 8
    2 5
    4 3
    3 9
    4 6
    

    输出样例:

    4

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    
    using namespace std;
    
    const int N = 1e5 + 10,M = N*2;
    
    //h表示链表头,e存储的是所有的边,ne表示所有的next指针是多少,相当与n个单链表
    int h[N],e[M],ne[M],idx,n;
    
    int ans = N;//全局的答案存储最小的最大值
    
    //深度优先搜索和宽度优先搜索每个点只会遍历一次
    bool st[N];//存一下那些点已经被遍历过了,就不要再遍历他了
    
    void add(int a,int b){//a前插入b
        e[idx] = b;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    
    //树和图的深度优先搜索的代码 时间复杂度是O(n + m),因为点数和边数呈线性关系
    //u表示已经遍历到这个节点了
    //以u为根的子树中点的数量
    int dfs(int u){
        st[u] = true;//首先先标记下当前这个点已经被搜索过了
        
        //记录当前子树的大小
        int sum = 1;
        int res = 0;//表示当前连通块的最小值的最大值
        
        //遍历下u的所有的初边
        for(int i = h[u];i != -1;i = ne[i]){
            // 存储当前结点对应图里边结点的编号是多少
            int j = e[i];
            //如果当前点没有做过的话,就一直搜,一条路走到黑
            if(!st[j]) {
                
                //表示当前子树的大小
                int s = dfs(j);
                
                //当前的子树也算是一个连通块
                res = max(res,s);
                //当前子树也是我们的子树的一部分
                //s为根的子树是以u为根节点的子树的一部分
                sum += s;
            }
        }
        
        res = max(res,n - sum);
        
        // cout << u << " " << sum;
        
        //最后res存的就是删除当前这个点之后所存储的最大的点数了
        ans = min(res,ans);
        
        return sum;
    }
    
    int main(){
        //头结点指向-1,n给单链表的头结点指向-1
        memset(h,-1,sizeof h);
        
        cin >> n;
        
        for(int i = 0;i < n - 1;i++){
            int a,b;
            cin >> a >> b;
            add(a,b),add(b,a);
        }
        
        dfs(1);//从第一个点开始搜索
        
        cout << ans;
    }
    

      

  • 相关阅读:
    细嚼慢咽C++primer(3)——引用形参,内联函数,重载函数,指向函数的指针
    面试突击(1)——数据结构基础,排序
    【Linux操作系统分析】进程的创建与可执行程序的加载
    List排序
    Dictionary 排序
    数据库连接串MSSQL、Oracle、Access
    String.IsNullOrEmpty()和String.IsNullOrWhiteSpace()
    jquery学习一 选择器
    sql查询问题
    int、string转enum;enum转int、string【C#】
  • 原文地址:https://www.cnblogs.com/luyuan-chen/p/11717545.html
Copyright © 2020-2023  润新知