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

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

  

posted @ 2019-10-22 05:29  香草味羊扒饭  阅读(351)  评论(0编辑  收藏  举报