題目:
給定一顆樹,樹中包含n個結點(編號1~n)和n-1條無向邊。
請你找到樹的重心,並輸出將重心刪除後,剩餘各個連通塊中點數的最大值。
重心定義:重心是指樹中的乙個結點,如果將這個點刪除後,剩餘各個連通塊中點數的最大值最小,那麼這個節點被稱為樹的重心。輸入格式第一行包含整數n,表示樹的結點數。
接下來n-1行,每行包含兩個整數a和b,表示點a和點b之間存在一條邊。
輸出格式
輸出乙個整數m,表示將重心刪除後,剩餘各個連通塊中點數的最大值。
資料範圍
1 ≤n
≤105
1≤n≤10^5
1≤n≤10
5輸入樣例
9
1 21 7
1 42 8
2 54 3
3 94 6
輸出樣例:
4
思路:本題最直觀的想法就是遍歷每乙個結點,然後將該結點刪除後,剩餘的幾個連通圖的分別求其結點個數,並取最大,作為該結點的結果,最終取最小的結果作為答案。如下圖,假設刪除結點4,則可以得到3個連通圖,我們發現最大的連通圖是由1、2、8、5、7組成的,因此刪除結點4後最大連通圖結點數為4。
但我們會發現,由於是樹形結構,因此每個結點都可以遞迴地獲得其所有孩子結點所在子樹連通圖的結點個數,而剩餘的結點就是整棵樹除了該結點所在子樹外的連通圖。如上圖,結點4的兩個孩子結點3和6所在的連通圖結點數分別是2和1,則剩下的結點數為:
9 (所
有結點數
)−2(
3、9結
點所在連
通圖)−
1(6結
點所在連
通圖)−
1(當前
結點4)
=5。9(所有結點數)-2(3、9結點所在連通圖)-1(6結點所在連通圖)-1(當前結點4)=5。
9(所有結點
數)−2
(3、9
結點所在
連通圖)
−1(6
結點所在
連通圖)
−1(當
前結點4
)=5。
因此,選擇深度優先遍歷實現對每個結點進行計數。
實現:
不選擇鄰接矩陣的原因是,本題的資料規模是 105
10^5
105,鄰接矩陣空間則為 1010
10^10
10,顯然會記憶體溢位。由於邊的個數為 n−1
n - 1
n−1,因此選擇鄰接表。
例如下圖:
深度優先遍歷,從任意乙個結點開始遍歷,並返回其所有子樹的結點個數的最大值,以及所有子樹的結點個數和即可。
本題需要注意的是,每次dfs時,不進行恢復現場,因為我們只要遍歷到乙個結點時,即可得到該結點所有子樹的結點個數,因此下一次不能再遍歷它。而恢復現場只適用於遍歷所有的可能的路徑。**實現:
#include
#include
#include
using
namespace std;
const
int n =
1e5+
5, m =
2* n;
// 如果用鄰接矩陣,則需要開闢1e^10空間,顯然不可以
// 所以使用模擬鄰接表儲存圖
// 分別表示結點陣列,插入到鄰接表的第idx個結點,第idx個結點的下乙個結點,以及結點編號idx
int h[n]
, e[m]
, ne[m]
, idx =0;
int vis[n]
;// 判斷當前結點是否已經被訪問過
int ans = n;
// 最終結果
int n, a, b;
// 插入乙個邊,a結點與結點b相連
void
add(
int a,
int b)
// dfs搜尋每乙個結點,並返回其所在子樹的所有結點個數
intdfs
(int x)
} res =
max(res, n - sum -1)
;// n-res-1表示根結點所有子樹(除了x及其子樹外)的結點數,最終取最大的結點數
ans =
min(res, ans)
;// 結果是要取最小的值
return sum +1;
}int
main()
樹的重心 DFS
include include include include include using namespace std const int maxn 1e5 10 vectorv maxn int subtree maxn 表示每點除去自身所對應的子樹大小 bool vis maxn 用以標記,去重...
演算法 樹的重心
樹的重心,也叫樹的質心。即樹的乙個點,以它為根時所有子樹最大子樹最小。刪去重心後,生成的多棵樹盡可能平衡。在樹的點分治中通常要用到。性質 樹中所有點到某個點的距離和中,到重心的距離和是最短的。如果有兩個重心,它們的距離和相等。把兩棵樹用一條邊相連,新的樹的重心在原來兩棵樹的重心的連線上。一棵樹新增或...
求樹的重心
題目 題意 給定一棵樹,求樹的重心的編號以及重心刪除後得到的最大子樹的節點個數size,如果size相同就選取編號最小的.分析 首先要知道什麼是樹的重心,樹的重心定義為 找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵 樹的重心,刪去重 心後,生成的多棵樹盡可能平衡.實際上樹的重心...