專題 樹的重心

2021-08-04 22:47:31 字數 2553 閱讀 3978

定義1:找到乙個點,刪除它得到的森林中最大的子樹節點數最少,那麼這個點就是這棵樹的重心。

定義2:刪除重心後得到的所有子樹,其頂點樹必然不超過n/2

性質1:樹中所有點到某個點的距離和中,到重心的距離和是最小的;如果有兩個重心,那麼他們的距離和一樣。

性質2:把兩個樹通過一條邊相連得到乙個新的樹,那麼新的樹的重心在連線原來兩個樹的重心的路徑上。

性質3:把乙個樹新增或刪除乙個葉子,那麼它的重心最多隻移動一條邊的距離。

根據定義,求解重心只需比較分別刪除每乙個結點後形成的森林中最大子樹的結點數,該指標最小的結點即為樹的重心。刪除某一結點x得到的子樹可以分成兩類,一類x的子樹,另一類是整棵樹中除去以x為根的子樹的部分。計算第一類的數量只需知道x的兒子有多少個子孫,計算第二類的數量只需知道x有多少個子孫。

因此核心問題就是知道這棵樹中每乙個結點有多少個子孫,這就是乙個樹型dp的問題,若son[i]表示i號結點的子孫數(不包含自己),則so

n[i]

=∑(s

on[j

]+1)

其中j為i的兒子。

只需dfs一遍這棵樹就可以求出son.

例1:poj 1655 balancing act

題目大意:給定一棵樹,求樹的重心的編號以及重心刪除後得到的最大子樹的節點個數size,如果size相同就選取編號最小的.

#include 

#include

#include

const

int inf=0x3f3f3f3f;

const

int maxn=20010;

const

int maxm=2*maxn;

using

namespace

std;

struct edge

e[maxm];

int n,head[maxn],edgenum;

int son[maxn],size,num;

bool vis[maxn];

void add_edge(int u,int v)

void dfs(int u)

}temp=max(temp,n-son[u]-1);//整棵樹除去以u為根的子樹的部分

if (temp//size維護刪除某一結點形成最大子樹結點數的最小值

num=u;//num維護重心編號

}}int main()

size=inf;num=0;

dfs(1);

printf("%d %d\n",num,size);

}return

0;}

例2:poj 3107 godfather

題目大意:給定一棵樹,求樹的所有重心,按照編號從小到大的順序輸出.

分析:與例1不一樣的地方只需每更新到乙個最小值的時候就記錄其它的最小值也為這個最小值的重心,這樣下去就會找到所有的重心。

#include 

#include

#include

#include

const

int maxn=50010;

const

int maxm=maxn*2;

const

int inf=0x3f3f3f3f;

using

namespace

std;

struct edge

e[maxm];

int n,edgenum,head[maxn];

int son[maxn],ans[maxn],size,cnt;

bool vis[maxn];

void add_edge(int u,int v)

void dfs(int u)

}temp=max(temp,n-son[u]-1);

if (temp1;

size=temp;

ans[cnt]=u;

}else

if (temp==size)//若一樣,把它記錄到ans陣列中

ans[++cnt]=u;

}int main()

size=inf;cnt=0;

memset(son,0,sizeof(son));

memset(vis,false,sizeof(vis));

dfs(1);

sort(ans+1,ans+cnt+1);//按編號公升序輸出

for (i=1;iprintf("%d ",ans[i]);

printf("%d\n",ans[cnt]);

return

0;}

樹的重心可以應用於樹的分治中。

由於刪除重心後得到的所有子樹,其頂點數必然不要過n/2。因此如果每次選擇重心進行分割,那麼每次樹的大小也至少減半,所以遞迴深度是o(log n),可以避免o(n2

)的極端複雜度。

樹的重心專題

解題思路 選擇乙個節點作為根,設dp i 表示以i為根的樹的總節點個數,dp i 滿足j為其子節點的的d j 之和再加1 根節點 只需在dfs過程中找到最大的子樹節點,並與其上方的節點數做比較,就可以找出樹的重心了。題目大意 對於一棵無根樹,找到乙個點使得樹以該點為根的有根樹,最大子樹 選擇該節點後...

求樹的重心

題目 題意 給定一棵樹,求樹的重心的編號以及重心刪除後得到的最大子樹的節點個數size,如果size相同就選取編號最小的.分析 首先要知道什麼是樹的重心,樹的重心定義為 找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵 樹的重心,刪去重 心後,生成的多棵樹盡可能平衡.實際上樹的重心...

模板 樹的重心

模板 求樹的重心 任務 求樹的重心 介面 vector way maxn 無向圖 int siz 該節點的子節點個數 包括自己 int mu 該節點的 最大,節點數最多 子樹的節點數 allnode 根節點的子節點個數 siz root int getroot int u,int fa 返回以u為根...