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 }

 

你可能感兴趣的:(HDU)