http://lightoj.com/volume_showproblem.php?problem=1094
树的直径是指树的最长简单路。
求法: 两遍BFS :先任选一个起点BFS找到最长路的终点,再从终点进行BFS,则第二次BFS找到的最长路即为树的直径;
原理: 设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点
证明:
1) 如果u 是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,则于BFS找到了v矛盾)
2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v 必然就是直径的后半段了
所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度
详细证明请参考:
http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html
#include <cstdio> #include <cstring> #include <ostream> #include <algorithm>using namespace std;#define N 30010struct Edge {int u, v, next, l; }edge[N * 4];int head[N], dist[N], Max, cnt, Index;void Init() {memset(head, -1, sizeof(head));cnt = 0; }void AddEdge(int u, int v, int l) {edge[cnt].u = u;edge[cnt].v = v;edge[cnt].l = l;edge[cnt].next = head[u];head[u] = cnt++; }void DFS(int u, int l) {int v, i;dist[u] = l;if(dist[u] > Max){Max = dist[u];Index = u;}for(i = head[u] ; i != -1 ; i = edge[i].next){v = edge[i].v;if(dist[v] == -1)DFS(v, edge[i].l + dist[u]);} }int main() {int t, n, u, v, l, i, x = 0;scanf("%d", &t);while(t--){x++;Init();scanf("%d", &n);for(i = 1 ; i < n ; i++){scanf("%d%d%d", &u, &v, &l);AddEdge(u, v, l);AddEdge(v, u, l);}Max = 0;memset(dist, -1, sizeof(dist));DFS(0, 0);//以树中任意一个结点为源点(这里暂且选0当源点),进行一次广度优先遍历,找出离源点距离最远的点Indexmemset(dist, -1, sizeof(dist));DFS(Index, 0);//以Index为源点,进行一次广度优先遍历,找出离Index最远的点,并记录其长度,该长度即为树的直径printf("Case %d: %d\n", x, Max);}return 0; }