樹的直徑 樹的重心

2022-06-01 18:48:09 字數 2208 閱讀 2435

樹的直徑

定義

那麼樹上最遠的兩個點,他們之間的距離,就被稱之為樹的直徑。

樹的直徑的性質

1. 直徑兩端點一定是兩個葉子節點。

2. 距離任意點最遠的點一定是直徑的乙個端點,這個基於貪心求直徑方法的正確性 可以得出。

3. 對於兩棵樹,如果第一棵樹直徑兩端點為(u,v),第二棵樹直徑兩端點為 (x,y),用條邊將兩棵樹連線,那麼新樹的直徑一定是u,v,x,y中的兩個點。

4. 對於一棵樹,如果在乙個點上接乙個葉子節點,那麼最多會改變直徑的乙個端 點。

5. 若一棵樹存在多條直徑,那麼這些直徑交於一點且交點是這些直徑的中點。

樹的直徑的求法

解法1:樹型dp

直接上**:

void dp(int x,int fa)

}

樹形dp有一些難理解,但他可以解決負邊權的問題

解法2:兩次dfs/bfs

上**:

void dfs(int x,int fa)

for(int i=head[x];i;i=e[i].next)

}

解法2運用了性質2,易理解,但不能處理負邊權問題。

上一道例題:

ac**:

#includeusing

namespace

std;

const

int n=1e5+5

;int

n,k;

inta,b;

intp;

int idx=1

;int

head[n];

intdis[n];

intpass[n];

intf[n];

int ans=0

;struct

nodee[n*2

];void add(int a,int

b)void dfs(int x,int

fa)

for(int i=head[x];i;i=e[i].next)

}void dp(int x,int

fa)}

intmain()

dfs(

1,0);

memset(dis,

0,sizeof

(dis));

memset(pass,

0,sizeof

(pass));

ans=0

; dfs(p,0);

if(k==1

)

int l1=ans;

ans=0

;

while

(pass[p])

dp(1,0);

cout

<<2*(n-1)-l1-ans+2

;

return0;

}

樹的重心

定義

樹的重心也叫樹的質心。對於一棵 個節點的無根樹,找到乙個點,使得把樹變成以該 點為根的有根樹時,最大子樹的結點數最小。換句話說,刪除這個點後最大連通塊(一定是 樹)的結點數最小,刪去重心後,生成的多棵樹盡可能平衡。

性質

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

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

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

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

思路

找到以i為根結點的最大子樹大小,與現在最小最大子樹相比較,不斷更新找出重心

//

minnode當前重心節點

//minbalance當前重心節點的最大子樹節點個數

intd[maxn];

//d[i]表示以i為根的子樹節點個數

void dfs(int u,int

fa) }

maxsub=max(maxsub,n-d[u]);

if(maxsub}

樹的重心 樹的直徑

樹的重心 樹的重心定義為 找到乙個點,其所有的子樹中最大的子樹節點數最少,那麼這個點就是這棵樹的重心,刪去重心後,生成的多棵樹盡可能平衡.實際上樹的重心在樹的點分治中有重要的作用,可以避免n 2的極端複雜度 從退化鏈的一端出發 保證nlogn的複雜度,利用樹型dp可以很好地求樹的重心.求樹的重心 模...

求樹的重心 樹的直徑

樹的重心 樹的重心是指樹上一點,去掉後最大子樹可以取得最小值的點。求解方法 樹的重心定義 去掉該點後最大子樹大小不超過n 2。重心為1 樹的直徑指樹上最遠兩點的距離 方法 先隨便找個點,找到離他最遠的點,再在那個最遠的點上找一次最遠的點,這兩個點之間的距離就是直徑。include define ma...

樹的直徑與重心

樹的直徑,指樹上最長的不重複經過同乙個點的路徑。方法 先從任意一點p pp出發,找離它最遠的點q qq,再從點q qq出發,找離它最遠的點w ww,w ww到q qq的距離就是的直徑 具體實現可以使用兩次dfs dfsdf s。演算法證明 反證法 include using namespace st...