zoukankan      html  css  js  c++  java
  • 树和图的深度优先搜索的模板框架

    #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;
    }
    

      

  • 相关阅读:
    Blender 3DOne
    [翻译]XNA外文博客文章精选之sixteen(中)
    实习技术员的基本功(二)
    [翻译]XNA外文博客文章精选之fifteen
    实习技术员的基本功(三)
    [翻译]XNA外文博客文章精选之sixteen(下)
    实习技术员的基本功(一)
    [翻译]XNA外文博客文章精选之sixteen(上)
    思维导图
    MySQL error 1045(28000): Access denied for user ...
  • 原文地址:https://www.cnblogs.com/luyuan-chen/p/11717545.html
Copyright © 2011-2022 走看看