树的深度优先遍历+树的重心

214 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

题目

www.acwing.com/problem/con… image.png

分析

image.png 问题:如何快速的求出来把每个点删掉后,最大值的最小者是多少?

  1. 在dfs中, 我们可以算出来每个子树的大小
  2. 以删掉4为例

数和图的DFS框架代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = N * 2;

int n, m;
int h[N], e[M], ne[M], idx; // e:存所有的结点的值; ne:存所有结点的next值是多少
bool st[N]; // 开一个bool数组存一下哪些点已经被遍历过了	

int ans; // 最小的最大值,全局的答案

// 插入一条a指向b的边,也就是在a对应的邻接表的表头插入b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}


void dfs(int u) // u表示当前已经dfs到的点
{
    st[u] = true; // 标记一下当前这个点已经被搜过了
    
    // 遍历一下u的所有出边
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i]; 
        if (!st[j]) dfs(j); // 如果j没有别搜过的话,就一条路走到黑
    }
}
	
int main()
{
    memset(h, -1, sizeof h); // 链表的初始化,将所有的头全部初始化为-1即可
  
    dfs(1); // 表示从第一点开始搜
}

本题代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = N * 2;

int n;
int h[N], e[M], ne[M], idx; // e:存所有的结点的值; ne:存所有结点的next值是多少
bool st[N]; // 开一个bool数组存一下哪些点已经被遍历过了	

int ans = N; // 最小的最大值,全局的答案

// 插入一条a指向b的边,也就是在a对应的邻接表的表头插入b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

// 返回以u为跟的子树里点的数量
int dfs(int u) // u表示当前已经dfs到的点
{
    st[u] = true; // 标记一下当前这个点已经被搜过了
    
    int sum = 1, res = 0;// sum:记录一下当前子树的大小 res:记录将该点删掉后,所有联通块中的最大值
    
    // 遍历一下u的所有出边
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i]; 
        if (!st[j]) 
        {
            // 如果j没有别搜过的话,就一条路走到黑
            int s = dfs(j);  // s表示当前子树的大小	
            res = max(res, s); // 因为当前子树也算一个联通块,所以也要跟res取一个max
            sum += s; 
        }
    }
    
    // 当前子树的上面那坨(n - sum)也要算
    res = max(res, n - sum);
    ans = min(ans, res);
    
    return sum;
}
	
int main()
{
    cin >> n;
    memset(h, -1, sizeof h); // 链表的初始化,将所有的头全部初始化为-1即可
  	
    for (int i = 0; i < n - 1; i++)
    {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }
    
    dfs(1); // 表示从第一点开始搜
    
    cout << ans << endl;
    
    return 0;	 
}