树间距离最长的两点所形成的路径叫做树的最长路
设这条路为s->t.
很容易想到的方法是以每个点为起点当做s,然后dfs求t。 时间复杂度是O(V*(V+E))
但有更简单的方法是,以任意点u进行dfs找到最远点,这个最远点为s或t,然后以这个最远点进行dfs,即可找到最长路
那么如何证明以任意点u进行dfs找到最远点,这个最远点为s或t呢??
为了写证明更简洁,我们设这点最远点为t
证明如下:
(1)点u为最长路s->t上的点,那么以u为起点搜到的最远点肯定为s或t,如果不是,那么很显然,s->t不是最长路
(2)点u不是最长路上的点,那么又分为两种情况
a:以点u搜到的最远点形成的路径与s->t有交点x,那么这条路的形成分为两个步骤,从u走到x,再从x搜最远点(又回到了第一种情况),
b:以点u搜到的最远点为T的路径与s->t没有交点,又因为图是联通的,那么可以从u走出一条路,该路与s->t有交点k。那么如图
那么 dist(u,T) > dist(u,k) + dist(k,t)
-->dist(u,T) > dist(k,t)
-->dist(u,T) + dist(s,k)+dist(u,k) > dist(k,t) + dist(s,k) = dist(s,t)
那么最长路就变成了dist(u,T) + dist(s,k)+dist(u,k)。与假设矛盾
所以又上面的证明可知,
以任意点u进行dfs找到最远点,这个最远点为s或t(以任意点出发的最长路与树的最长路一定有交点)
http://lx.lanqiao.org/problem.page?gpid=T32
1 #include <stdio.h> 2 #include <string.h> 3 #include <vector> 4 using namespace std; 5 const int N = 10000 + 10; 6 struct node 7 { 8 int v,next,cost; 9 }g[N*2]; 10 int e,head[N]; 11 bool vis[N]; 12 void addEdge(int u, int v, int cost) 13 { 14 g[e].v = v; 15 g[e].cost = cost; 16 g[e].next = head[u]; 17 head[u] = e++; 18 } 19 int maxDist,index; 20 void dfs(int u, int dist) 21 { 22 if(dist > maxDist) 23 { 24 maxDist = dist; 25 index = u; 26 } 27 for(int i=head[u]; i!=-1; i=g[i].next) 28 { 29 int v = g[i].v; 30 if(!vis[v]) 31 { 32 vis[v] = true; 33 dfs(v,dist+g[i].cost); 34 vis[v] = false; 35 } 36 37 } 38 } 39 int main() 40 { 41 int n,u,v,c,i; 42 scanf("%d",&n); 43 memset(head,-1,sizeof(head)); 44 for(i=1; i<n; ++i) 45 { 46 scanf("%d%d%d",&u,&v,&c); 47 addEdge(u,v,c); 48 addEdge(v,u,c); 49 } 50 memset(vis,0,sizeof(vis)); 51 vis[i] = true; 52 dfs(i,0); 53 memset(vis,0,sizeof(vis)); 54 vis[index] = true; 55 dfs(index,0); 56 printf("%d ",maxDist*10 + (1+maxDist)*maxDist/2); 57 return 0; 58 }