題目描述
給定一顆樹,樹中包含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;
}