填坑行動6 樹的重心

2022-07-06 16:06:11 字數 1196 閱讀 6305

目錄對於一棵樹無根樹,找到乙個點,使得把樹變成以該點為根的有根樹時,最大子樹的結點數最小。換句話說,刪除這個點後最大連通塊(一定是樹)的結點數最小。

樹的重心不唯一。

樹中所有點到某個點的距離和中,到重心的距離和是最小的,如果有兩個重心,他們的距離和一樣。

把兩棵樹通過一條邊相連,新的樹的重心在原來兩棵樹重心的連線上。

一棵樹新增或者刪除乙個節點,樹的重心最多隻移動一條邊的位置。

一棵樹最多有兩個重心,且相鄰。

從上面可以得出,樹的重心是樹上的乙個節點並且去掉這個節點的時候,剩下的連通塊中,最大連通塊中節點數最小,我們可以從這一點入手。

這裡使用樹形dp的方式來計算樹的重心。

令這棵樹的節點\(1\)為根(其實什麼節點都可以),\(f_i\)為根節點\(i\)的節點數量。那麼以這個點\(i\)為根,點\(i\)的兒子依次為\(a_1,a_2,a_3 \dots a_n\),那麼剩下的連通塊的節點數分別為$$f_\ ,\ f_\ ,\ f_\ ,\ n-\sum_^f_-1$$

令節點\(i\)的兒子依次為\(a_1,a_2,a_3 \dots a_n\),那麼我們可以得出$$f_i\ =\ \sum_^f_+1$$

然後直接一趟dfs就完事了。

**如下:

#include#include#define max(a,b) ((a)>(b)?(a):(b))

#define min(a,b) ((a)<(b)?(a):(b))

#define maxn 200039

using namespace std;

int head[maxn],to[maxn],nex[maxn],k;

#define add(x,y) nex[++k]=head[x];\

head[x]=k;\

to[k]=y;

int n,minx,node;//node 是樹的重心(不唯一)

int u,v,f[maxn];

void dfs(int num,int pre)

maxx=max(f[num],n-f[num]);

if(maxxreturn;

}int main()

minx=0x7fffffff;

dfs(1,0);

printf("%d %d",minx,node);

return 0;

}

填坑行動5 最小生成樹kruskal 學習筆記

目錄題目描述 如題,給出乙個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz。輸入格式 第一行包含兩個整數 n,m 表示該圖共有 n 個結點和 m 條無向邊。接下來 m 行每行包含三個整數 x i,y i,z i 表示有一條長度為 z i 的無向邊連線結點 x i,y i x。輸出格式 如果該圖...

BZ2599(樹分治填坑)

第一次寫樹分治.剛開始被屬於同一分支的點通過根組成的鏈坑了一發.然後又被陣列下標從零開始坑了一發.最後陣列大小多寫了個0又mle了一發.感覺有點難看將就一下吧.include include using namespace std const int n 200050,m 1000050 int n...

求樹的重心

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