*总结的别人博客
树的直径(Diameter)是指树上的最长简单路。
直径的求法:两遍BFS (or DFS)
任选一点u为起点,对树进行BFS遍历,找出离u最远的点v
以v为起点,再进行BFS遍历,找出离v最远的点w。则v到w的路径长度即为树的直径
*简单证明
于是原问题可以在O(E)时间内求出
关键在于证明第一次遍历的正确性,也就是对于任意点u,距离它最远的点v一定是最长路的一端。
如果u在最长路上,那么v一定是最长路的一端。可以用反证法:假设v不是最长路的一端,则存在另一点v’使得(u→v’)是最长路的一部分,于是len(u→v’) > len(u→v)。但这与条件“v是距u最远的点”矛盾。
如果u不在最长路上,则u到其距最远点v的路与最长路一定有一交点c,且(c→v)与最长路的后半段重合(why?),即v一定是最长路的一端
BFS
DFS
一张无向图中,给定图中一点,以最短路径长度当作距离,找出改点最远的一点,这两点之间的距离就叫做偏心距。
要计算一张无向图的半径,只要先算好两点之间最短路径,然后按定义来算即可。
先用floyd 再搜索最长的路径(即为直径)。
1 int d[10][10]; // adjacency matrix 2 int ecc[10]; // 各點的偏心距 3 4 void diameter_radius() 5 { 6 // Floyd-Warshall Algorithm 7 for (int k=0; k<10; ++k) 8 for (int i=0; i<10; ++i) 9 for (int j=0; j<10; ++j) 10 d[i][j] = min(d[i][j], d[i][k] + d[k][j]); 11 12 // 計算偏心距 13 memset(ecc, 0x7f, sizeof(ecc)); 14 for (int i=0; i<10; ++i) 15 for (int j=0; j<10; ++j) 16 ecc[i] = min(ecc[i], d[i][j]); 17 18 // 計算直徑和半徑 19 int diameter = 0; 20 int radius = 1e9; 21 for (int i=0; i<10; ++i) 22 { 23 diameter = max(diameter, ecc[i]); 24 radius = min(radius , ecc[i]); 25 } 26 27 /* 28 // 直徑也可以這樣算 29 for (int i=0; i<10; ++i) 30 for (int j=0; j<10; ++j) 31 diameter = max(diameter, d[i][j]); 32 */ 33 }
floyd
一棵樹的各種直徑一定會相交在同一點(同一群點)。
1. 反證法。 現在有兩條分開的直徑, 可是一棵樹上各點都得連通, 所以這兩條分開的直徑,中間一定有某處互相連接, 一旦連接起來,勢必變成更長的直徑,矛盾。 故所有直徑必相交。 2. 反證法。 現在已有兩條直徑相交在某一點, 如果另外一條直徑與這兩條直徑相交在另一點, 勢必變成更長的直徑,矛盾。 故所有直徑必相交在同一點(同一群點)。
时间: 2024-10-23 20:24:09