講解的方法是按照我自己的理解來的,有任何沒有說清楚的地方歡迎提問。
-----------------------------------------------------------------------------------------------------
網上將有關的題目不少,但是詳細講這個算法的人不多。自己對着代碼琢磨了一下,對這個算法講一講自己的理解。
首先,我們需要明白什麼是樹的中心。
先定義 |T| 爲樹T中結點的個數。
樹的中心:將某個點V從樹T中刪除(連接這個點的邊自然也刪除了),會形成若干棵子樹,其中結點個數最多的子樹我們稱其爲最大子樹M。如果該結點被刪除使得 |M| < | 其他結點被刪除得到的最大子樹 |,則把V 稱爲樹的中心。
那麼,如何求樹的中心呢,其實根據定義就行,挨個結點刪除試試。而在實際操作中,我們不需要刪除結點也能知道這棵樹所有子樹的大小,用刪除這個詞只是爲了便於理解。
採用DFS來實現這個算法。
typedef vector<int>::iterator vc_i;
int center = -1;
vector<int> G[N];
int n;//樹的結點總數
int sz[N]; //記錄每個結點按其深搜方向所形成的樹的節點個數。
int maxSub[N];//記錄刪除某個節點後所形成的所有子樹中結點最多的子樹的結點數量
void dfs(int cur, int pre)
{
sz[cur] = 1;
maxSub[cur] = 0;
for(vc_i i = G[cur].begin(); i != G[cur].end(); i++)
{
int v = *i;
if(v == pre) continue;
dfs(v, cur);
sz[cur] += sz[v];
maxSub[cur] = max(maxSub[cur], sz[v]);
}
maxSub[cur] = max(maxSub[cur], n - sz[cur]); //在整個過程中,我們搜索的子樹漏掉了一棵,想想是哪棵? 看看continue那裏就能想明白了
if(center == -1 || maxSub[cur] < maxSub[center])
center = cur;
}
但是這個方法求樹的中心有侷限,即你一定要先知道一共有多少個樹結點。
而通過下面的性質④,可以不需要知道結點總數從而得到中心。
接下來說一些樹的中心的性質,主要參考該鏈接:樹的“重心”的一些性質及動態維護 。
①樹中所有點到某個點的距離和中,到重心的距離和是最小的;如果有兩個重心,那麼他們的距離和一樣。
②把兩個樹通過一條邊相連得到一個新的樹,那麼新的樹的重心在連接原來兩個樹的重心的路徑上。
③把一個樹添加或刪除一個葉子,那麼它的重心最多隻移動一條邊的距離。
④樹的中心一定在樹的直徑上。