树的重心

题目描述

给定一颗树,树中包含n个结点(编号1~n)和n-1条无向边。
请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。
重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

输入格式

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

输出格式

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

数据范围

1≤n≤105

输入样例

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

输出样例:

4

解题思路
这道题就是树的深度优先遍历,我们只需套用模板,遍历每个点的同时,返回该子树的点的个数,以及计算去掉该点时连通块点的最大值即可,最后用ans取最大联通的最下值即可。
具体代码如下:

#include
#include
using namespace std;
const int N  = 1e6 + 10;
int h[N], e[N], ne[N], idx, n;
int ans = N;  //答案
bool vis[N];  //判断是否遍历过
void add(int a, int b)  //邻接表存树与图
{
     
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
int dfs(int cur)
{
     
    vis[cur] = true;
    int res = 0, sum = 1;  //res表示去掉cur这个节点,联通块点的最大值, sum表示该子树点的个数
    for(int i = h[cur]; i != -1; i = ne[i]){
       //遍历树
        int u = e[i];
        if(!vis[u]){
     
            int s = dfs(u);
            res = max(res, s);
            sum += s;
        }
    }
    res = max(res, n - sum);  // sum是该子树的点的个数, n - sum表示它的父节点所连接的联通块点的个数
    ans = min(res, ans);  //取最大连通块点的最小值
    return sum;
}
int main()
{
     
    int a, b;
    cin >> n;
    //初始化
    memset(h, -1, sizeof h);
    memset(vis, false, sizeof vis);
    for(int i = 0; i < n; i++){
     
        cin >> a >> b;
        //建树,双向图
        add(a, b);
        add(b, a);
    }
    dfs(1);
    cout << ans << endl;
    return 0;
}

你可能感兴趣的:(数据结构与算法题解总集)