題意:
輸入檔案包含多組測試資料。對於每組測試資料,第一行乙個整數n (n<=10000),接下來有n-1行,每一行兩個數,對於第i行的兩個數,它們表示與i號電腦連線的電腦編號以及它們之間網線的長度。網線的總長度不會超過10^9,每個數之間用乙個空格隔開。
輸出:
對於每組測試資料輸出n行,第i行表示i號電腦的答案 (1<=i<=n).
輸入樣例:
51 1
2 13 1
1 1輸出樣例:32
344解題思路:
這是關於樹的直徑的應用問題。樹的直徑被定義為樹中任意兩點之間距離的最大值,先明確一點是樹的直徑一定是某兩個葉子之間的距離,我們需要從樹中任選乙個點(注意是任意乙個點,我們這裡就選1號電腦)開始遍歷這棵樹,找到乙個距離這個點最遠的葉子,然後再從這個葉子開始遍歷,找到離這個葉子最遠的另乙個葉子,他倆之間的距離就是樹的直徑。通過兩次遍歷即可求出樹的直徑。這裡的遍歷可以用dfs(遞迴實現)也可以用bfs(佇列實現),找到距離起點最遠的葉子結點即可。即:假設樹的最長路的兩個葉子節點為v1, v2,從任意一點 u 出發走到的最遠的點一定是(v1,v2)中的一點,然後再從 v1 或者 v2 出發走到的最遠點則一定是 v2 或者 v1。由此經過兩次遍歷就能找到最長路徑。這道題不是找最長路徑,而是找某個節點 x 所能到達的最長路徑。首先這個節點 x 的最長路徑要麼是到 v1 的路徑,要麼就是到 v2 的路徑。我們分別從 v1, v2 兩點進行遍歷,求得到各個點的距離,然後分別比較每個距離挑出較大的那乙個距離即可。
注意事項:
1、首先需要兩次dfs找到樹直徑的兩端即v1和v2,然後不要對每個點進行兩次到v1和v2的遍歷,應該分別從 v1, v2 兩點進行遍歷,求得到各個點的距離之後再分別比較每個距離挑出較大的那乙個距離來。
2、所有會重複使用的資料結構或資料型別在每次初始化時一定要復原,如這道題的max_dis,vis陣列,dis陣列等。
總結:
這是關於樹的直徑的應用問題,用dis陣列記錄距離,注意需要單獨用乙個bool型別陣列vis來記錄每個點是否被訪問過。不同的dfs思想類似,均是遞迴實現dfs遍歷,但具體實現時注意有細微區別,這裡我們用了函式dfs、dfs2、dfs3。
參考**:
#include
#include
#include
using
namespace std;
int n,v1,v2;
struct edge
;vector v[
10010];
int dis[
10010];
int dis2[
10010];
bool vis[
10010];
void
ini(
)int max_dis=-1
;void
dfs(
int p,
int flag)
if(flag==1)
dfs(v[p]
[i].v,1)
;else
dfs(v[p]
[i].v,2)
;}}}
void
dfs2
(int p)}}
void
dfs3
(int p)}}
intmain
(int argc,
const
char
* ar**)
);v[num]
.push_back()
;}dfs(1,
1);//cout;memset
(dis,0,
sizeof
(dis));
ini();
dfs(v1,2)
;//cout(dis,0,
sizeof
(dis));
ini();
dfs2
(v1)
;memset
(dis2,0,
sizeof
(dis));
ini();
dfs3
(v2)
;for
(int i=
1;i<=n;i++)}
return0;
}
樹直徑問題
我們把一棵樹的最長的路徑稱作為數的直徑。怎麼求數的直徑?1 從任意乙個節點出發,用bfs或者dfs遍歷,找到最長路徑的最後乙個點,那個就是直徑的乙個端點a。2 從乙個端點a出發,再次使用bfs或者dfs遍歷,找到最長路徑的最後乙個點,就是直徑的另外乙個端點b。也就是要兩次遍歷。這個,最直觀的思路就是...
SDOI2013 直徑(樹的直徑)
小q最近學習了一些圖論知識。根據課本,有如下定義。樹 無迴路且連通的無向圖,每條邊都有正整數的權值來表示其長度。如果一棵樹有n個節點,可以證明其有且僅有n 1 條邊。路徑 一棵樹上,任意兩個節點之間最多有一條簡單路徑。我們用 dis a,b 表示點a和點b的路徑上各邊長度之和。稱dis a,b 為a...
樹的直徑 板子
不帶解釋版模板o n 常數較大,但是可以知道樹上每一點到直徑端點的距離,這個大多時候都很有用 struct node e maxn 2 ll dis1 maxn dis2 maxn int st,ed,max len void dd int u,int fa,int len,int flag fil...