在一個有n個節點,n-1條無向邊的無向圖中,求圖中最遠兩個節點的距離,那么將這個圖看做一棵無根樹,要求的即是樹的直徑。####
求樹的直徑主要有兩種方法:樹形dp和兩次bfs/dfs,因為我太菜了不會寫后者這里只介紹樹形dp
-
樹形dp求樹的直徑
我們不妨設1號點為根節點,那么這就可以看做一棵有根樹。
設D[x]表示從節點x出發,往以x為根的子樹走,能夠到達的最遠距離。設x的子節點分別為\(y_1,y_2,y_3,...,y_t\),\(edge(x,y)\)表示從x到y的邊權,則可以得到狀態轉移方程:
\(D[x]={(D[y_i]+edge(x,y_i))}_{max}\)
接下來,我們考慮對於每個節點x求出經過x的最長鏈的長度F[x],整棵樹的直徑就是max{F[x]}(1<=x<=n)。現在我們考慮如何求F[x]。
對於任意兩個節點yi和yj,經過節點x的最長鏈的長度可以通過四個部分來構成:- D[yi]
- D[yj]
- 從x到yi的距離
- 從x到yj的距離
不妨設j<i,則有:
\(F[x]= {(D[y_i]+D[y_j]+edge(x,y_i)+edge(x,y_j))}_{max}\)
對應代碼如下:
void dp(int x){
v[x]=1;
for(register int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(v[y])continue;
dp(y);
ans=max(ans,d[x]+d[y]+edge[i]);
d[x]=max(d[x],d[y]+edge[i]);
}
}
代碼解釋可以看圖:
參考資料:李煜東《算法競賽進階指南》