码迷,mamicode.com
首页 > 其他好文 > 详细

牡丹江.2014B(图论,树的直径)

时间:2015-08-17 23:03:21      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:

B - Building Fire Stations
Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu
Appoint description: 

Description

Marjar University is a beautiful and peaceful place. There are N buildings and N - 1 bidirectional roads in the campus. These buildings are connected by roads in such a way that there is exactly one path between any two buildings. By coincidence, the length of each road is 1 unit.

To ensure the campus security, Edward, the headmaster of Marjar University, plans to setup two fire stations in two different buildings so that firefighters are able to arrive at the scene of the fire as soon as possible whenever fires occur. That means the longest distance between a building and its nearest fire station should be as short as possible.

As a clever and diligent student in Marjar University, you are asked to write a program to complete the plan. Please find out two proper buildings to setup the fire stations.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer N (2 <= N <= 200000).

For the next N - 1 lines, each line contains two integers Xi and Yi. That means there is a road connecting building Xi and building Yi(indexes are 1-based).

Output

For each test case, output three integers. The first one is the minimal longest distance between a building and its nearest fire station. The next two integers are the indexes of the two buildings selected to build the fire stations.

If there are multiple solutions, any one will be acceptable.

Sample Input

2
4
1 2
1 3
1 4
5
1 2
2 3
3 4
4 5

Sample Output

1 1 2
1 2 4

 

 
技术分享
 1 //#pragma comment(linker, "/STACK:1024000000,1024000000") 
 2 using namespace std ;
 3 const int M = 2e5 + 10 , inf = 111111111 ;
 4 struct node {
 5         int L , R ;
 6         int dl , dr ;
 7         node () {}
 8         node (int L , int R , int dl , int dr) :
 9                 L(L) , R(R) , dl(dl) , dr(dr) {}
10 }a[M] ;
11 int id , maxn ;
12 int n ;
13 vector<int> g[M] ;
14 bool vis[M] ;
15 vector<int> path ;
16 int N ;
17 int dfs (int o , int u) {
18         a[u] = node (u , u , 1 , 1) ;
19         for (vector<int>::iterator v = g[u].begin () ; v != g[u].end () ; v ++) {
20                 if (*v == o) continue ;
21                 int tmp = 1 + dfs (u , *v) ;
22                 if (tmp > a[u].dl) a[u] = node (a[*v].L , a[u].L , tmp , a[u].dl) ;
23                 else if (tmp > a[u].dr) a[u].R = a[*v].L , a[u].dr = tmp ;
24         }
25         if (a[u].dl + a[u].dr > maxn) maxn = a[u].dl + a[u].dr , id = u ;
26         return a[u].dl ;
27 }
28 
29 bool PATH (int o , int u) {
30         for (vector<int>::iterator v = g[u].begin() ; v != g[u].end () ; v ++) {
31                 if (*v == o) continue ;
32                 if (PATH (u , *v)) {path.push_back (u) ; return true ;} 
33         }
34         if (u == a[id].R) {path.push_back (u) ; return true ;} 
35         return false ;
36 }
37 
38 void DFS (int o , int u , int dep , int deep) {
39         if (dep > deep) return ;
40         vis[u] = 1 ;
41         for (vector<int>::iterator v = g[u].begin() ; v != g[u].end () ; v ++) {
42                 if (*v == o) continue ;
43                 DFS (u , *v , dep+1 , deep) ;
44         }
45 }
46 
47 bool judge (int x) {
48         memset (vis , 0 , sizeof(vis)) ;
49         DFS (-1 , path[x] , 0 ,  x ) ;
50         DFS (-1 , N-x-1 == x ? path[x+1] : path[N-x-1] , 0 , x ) ;
51         //printf ("x = %d\n" , x ) ;
52         //if (x == 1) for (int i = 1 ; i <= n ; i ++) if (!vis[i]) printf ("geng shi %d\n" , i ) ;
53         for (int i = 1 ; i <= n ; i ++) if (!vis[i]) return false ;
54         return true ;
55 }
56 
57 void solve () {
58         N = path.size () ;
59         int l = 0 , r = N / 2 ;
60         int ret = r ;
61         //printf ("l = %d , r = %d\n" , l , r) ;
62         while (l <= r) {
63                 int mid = l + r >> 1 ;
64                 if (judge (mid)) {
65                         ret = mid ;
66                         r = mid - 1 ;
67                         //printf ("ret = %d\n" , ret ) ;
68                 }
69                 else l = mid + 1 ;
70         }
71         printf ("%d %d %d\n" , ret , path[ret] , ret == N-ret-1 ? path[ret+1] : path[N-ret-1] ) ;  
72 }
73 
74 int main () {
75         int T ;
76         scanf ("%d" , &T ) ;
77         while (T --) {
78                 scanf ("%d" , &n) ;
79                 path.clear () ;
80                 for (int i = 0 ; i <= n ; i ++) g[i].clear () ;
81                 for (int i = 0 ; i < n - 1 ; i ++) {
82                         int u , v ;
83                         scanf ("%d%d" , &u , &v) ;
84                         g[u].push_back (v) ;
85                         g[v].push_back (u) ;
86                 }
87 
88                 maxn = -1 ;
89                 dfs (-1 , 1) ;
90                 //printf ("Dia = %d , Lnode = %d , Rnode = %d\n" , maxn-1 , a[id].L , a[id].R) ;
91                 PATH (-1 , a[id].L) ;
92                 //for (vector<int>::iterator it = path.begin() ; it != path.end() ; it ++) printf ("%d " , *it) ; puts ("") ;
93                 solve () ;
94         }
95         return 0 ;
96 }
View Code

因为可行的两个点肯定是在树的直径上(对称的两点),所以我们可以二分答案,最优解肯定在0~dia/2 内。

另外找直径的方法可以换一下,可以从任意一点搜到任意一个深度最大的点v,在从v开始搜搜到此时深度最大的点u,则u,v就是树直径的两个端点。

我的方法是:

对于任何一个节点,他都有一个最深,和次深子节点L,R。所以从任意一个点u出发,用u的两个最深的子节点来更新,u.dl= v1.dl+1 , u.dr = v2.dl + 1 ;

u.L = v1 , u.R = v2 (深度(V1) >= 深度 (V2) ) ;

这样找一遍dfs就可以知道Dia是多少,并且知到该直径的两个端点分别是谁。

缺点是打印Dia路径时,需要再写一个dfs,hhhhh

还要注意,zoj坑爹的栈深度很低,20w就爆了,所以想要dfs过的话,就去cf上交吧:http://codeforces.com/gym/100554/problem/B 

 

牡丹江.2014B(图论,树的直径)

标签:

原文地址:http://www.cnblogs.com/get-an-AC-everyday/p/4737863.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!