hdu 4607 Park Visitは木の直径を求めます。

13341 ワード

テーマリンク:http://acm.hdu.edu.cn/showproblem.php?pid=4607
Clire and her little friend、ykwd、artravelling in Shevcheck's Park!The park is beautiful-but large,indeed.N feature spots in the parkarararararare e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e e pargs,and Clire istototired to visit t t a a them.Afterconsidededededededidididididididididididididididididididididididedededededededed d d ininininininininininininininininininine e e e e them.Aft them.Afttttttttttttttttttrancs at each feature spot!Clire wants to chose an entrance、and find a way of visit to minimize the distance she has to walk.For convence、we can assine the length of all paths are 1.
Clire is too tired.Can you help her?
 
子供たちは公園で遊んでいます。公園にはNの観光スポットがあります。今、子供たちはその中のkつの観光スポットを見学したいです。そして、歩く道が一番短いです。最短経路を求める
アルゴリズム解析:まずこれは無方向連結図であり、樹形構造のような形をしていることを知っている。もし公園に長い道があったら、kより大きい観光スポットの数が含まれています。この時、k-1の観光スポットを歩く一番短いルートはk-1です。k個がないなら、できるだけ少ない観光スポットを別の道にしたいです。これにより、木の直径を求めるということが考えられます。(ツリーの直径の証明についてはネットでもたくさんあります)
木の直径のアルゴリズムを求めます。木の直径は木の一番長い簡単な道を指します。
法を求めます:2回のBFS:先に選んで1つの起点BFSを選んで最も長い道の終点を探し当てて、更に終点からBFSを行って、第2回のBFSの探し当てる最も長い道はつまり木の直径です。
原理:起点をuとし、初めてBFSで見つけた終点vは木の直径の一つの端点である。
証明:1)uが直径上の点であれば、vは明らかに直径の終点である(vがそうでなければ、他の点wが必ず存在し、uからwまでの距離が長くなると、BFSがv矛盾を見つけたから)
2)uが直径上の点でないと、uからvは必ず木の直径と交差します。交点からvまでは必ず直径の後半です。vは直径の一つの端点です。だから、vからBFSを行って得られるのは直径の長さです。
 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cstring>

 4 #include<cstdlib>

 5 #include<cmath>

 6 #include<algorithm>

 7 #include<queue>

 8 #define inf 0x7fffffff

 9 using namespace std;

10 const int maxn=100000+10;

11 const int M = 100000+10;

12 

13 int n,m;

14 struct node

15 {

16     int v,w;

17     int next;

18 }edge[M*3];

19 int head[maxn],edgenum;

20 

21 void add(int u,int v,int w)

22 {

23     edge[edgenum].v=v ;edge[edgenum].w=w ;

24     edge[edgenum].next=head[u] ;head[u]=edgenum++ ;

25 

26     edge[edgenum].v=u ;edge[edgenum].w=w ;

27     edge[edgenum].next=head[v] ;head[v]=edgenum++ ;

28 }

29 

30 int vis[maxn],d[maxn];

31 int bfs(int from)

32 {

33     queue<int> Q;

34     Q.push(from);

35     memset(d,-1,sizeof(d));

36     memset(vis,0,sizeof(vis));

37     d[from]=1;

38     vis[from]=1;

39     int maxlen=-1,k=0;

40     while (!Q.empty())

41     {

42         int u=Q.front() ;Q.pop() ;

43         for (int i=head[u] ;i!=-1 ;i=edge[i].next)

44         {

45             int v=edge[i].v;

46             if (!vis[v])

47             {

48                 vis[v]=1;

49                 d[v]=d[u]+1;

50                 if (d[v]>maxlen)

51                 {

52                     maxlen=d[v];

53                     k=v;

54                 }

55                 Q.push(v);

56             }

57         }

58     }

59     return k;

60 }

61 

62 int main()

63 {

64     int t;

65     scanf("%d",&t);

66     while (t--)

67     {

68         memset(head,-1,sizeof(head));

69         edgenum=0;

70         int a,b;

71         scanf("%d%d",&n,&m);

72         for (int i=1 ;i<=n-1 ;i++)

73         {

74             scanf("%d%d",&a,&b);

75             add(a,b,1);

76         }

77         int v=bfs(1);

78         int u=bfs(v);

79         int maxlen=d[u];

80         //cout<<"debug= "<<maxlen<<endl;

81         for (int i=0 ;i<m ;i++)

82         {

83             scanf("%d",&a);

84             if (a<=maxlen) printf("%d
",a-1); 85 else printf("%d
",maxlen-1+(a-maxlen)*2); 86 } 87 } 88 return 0; 89 }