樹的直徑
定義
那麼樹上最遠的兩個點,他們之間的距離,就被稱之為樹的直徑。
樹的直徑的性質
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**:
#includeusingnamespace
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...