樹的重心

題目描述

給定一顆樹,樹中包含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<iostream>
#include<cstring>
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章