hdu 4607 树的直径

思路:先求出树的直径,如果k比较小,则显然在直径上走是最优的。如果k比较多的话,意味着我们要走“往返路”去访问一些结点,则很显然最优解是使得走“往返路”访问的结点的数量最少,于是我们考虑在直径上走,不够的点我们通过走往返路去访问,这样可以使得不走往返路就访问的点(直径上的点)最多,也就是走往返路访问结点最少,是最优解。

树的直径的求法:先任取一点,求离该点最远的点u,则u一定为直径的两个端点之一,然后求出离u点最远的点,二者距离便是直径。

证明见:http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 
 6 const int N = 100001;
 7 int head[N];
 8 int n, m, e;
 9 int node, dist;
10 
11 struct Edge
12 {
13     int v, next;
14 } edge[N * 2];
15 
16 void addEdge( int u, int v )
17 {
18     edge[e].v = v;
19     edge[e].next = head[u];
20     head[u] = e++;
21 }
22 
23 void dfs( int u, int fa, int depth )
24 {
25     if ( depth > dist )
26     {
27         dist = depth;
28         node = u;
29     }
30     for ( int i = head[u]; i != -1; i = edge[i].next )
31     {
32         int v = edge[i].v;
33         if ( v == fa ) continue;
34         dfs( v, u, depth + 1 );
35     }
36 }
37 
38 int main ()
39 {
40     int t;
41     scanf("%d", &t);
42     while ( t-- )
43     {
44         scanf("%d%d", &n, &m);
45         e = 0;
46         memset( head, -1, sizeof(head) );
47         for ( int i = 1; i < n; i++ )
48         {
49             int u, v;
50             scanf("%d%d", &u, &v);
51             addEdge( u, v );
52             addEdge( v, u );
53         }
54         dist = -1;
55         dfs( 1, -1, 0 );
56         dist = -1;
57         dfs( node, -1, 0 );
58         while ( m-- )
59         {
60             int k, ans;
61             scanf("%d", &k);
62             if ( k <= dist + 1 ) ans = k - 1;
63             else ans = dist + ( k - dist - 1 ) * 2;
64             printf("%d\n", ans);
65         }
66     }
67     return 0;
68 }

 

posted @ 2015-07-24 12:07  hxy_has_been_used  阅读(213)  评论(0编辑  收藏  举报