树的直径(最长路)

树间距离最长的两点所形成的路径叫做树的最长路

设这条路为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\n",maxDist*10 + (1+maxDist)*maxDist/2);
57     return 0;
58 }
View Code

 

posted @ 2015-03-24 17:05  justPassBy  阅读(402)  评论(0)    收藏  举报