zoj3820 树直径上二分选点
来源:互联网 发布:淘宝已有图片找同款 编辑:程序博客网 时间:2024/05/06 03:17
Building Fire Stations
Time Limit: 5 Seconds Memory Limit: 131072 KB Special Judge
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
题意:有n个建筑,n-1条边将n个建筑连接起来,每条边成都为1,现在要选择两个建筑点设立消防站,为了使距离消防站最远的建筑 距离消防站的距离最小,该怎样选择那两个站点设立消防站,输出这个最小的最大距离以及这两个站点。
如果是一条链的话很明显,将链三等分的两个点便是了。
如果是一颗树的话,道理也是一样的,肯定在树的直径上,但是不一定是数的直径的三等分点,但可以肯定的是这两个点是关于直径中点对称的。
我们只需要找一个点就可以了,另外一个点关于重点对称,而找树的直径很简单,随意从一个s1点出发,找到距离这个点最远的点s2,再从s2出发找到距离s2最远的点s3,那么s2到s3的路径便是树的直径。
把树的直径用数组保存下来,在这个直径上进行二分,设k1为第一个点的下标,那么第二点的下标 k2=m(直径上的点总数)-k1-1,当满足从road[k1]**或则**road[k2]到其余所有到点小于k1时(k1刚好就是从第0个点到k1点的距离),k1左移(二分意义上的左移),否则k1右移,二分的复杂度是logn,而遍历查询每个点到road[k1],road[k2]距离是n,所以时间是可以接受的。如果k1==k2,随便给k2附一个值,因为如果取中点,另外一个点取哪个都可以,不会影响中间的选择。
代码:
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <algorithm>#include <string.h>#include <queue>using namespace std;const int Maxn=200000+100;const int inf=0x3f3f3f3f;struct Edge{ int to,cap,next;} edge[Maxn*2];int head[Maxn],tot,N;void init(){ tot=0; memset(head,-1,sizeof(head));}void addedge(int u,int v,int w){ edge[tot].to=v; edge[tot].cap=w; edge[tot].next=head[u]; head[u]=tot++;}int dis[Maxn],vis[Maxn],pre[Maxn];int road[Maxn],sum;int bfs(int s){ int v,u,max_d=0,res; queue<int>que; que.push(s); memset(vis,0,sizeof(vis)); vis[s]=1; while(!que.empty()) { u=que.front(); que.pop(); for(int i=head[u]; i!=-1; i=edge[i].next) { v=edge[i].to; if(!vis[v]) { dis[v]=dis[u]+1; if(dis[v]>max_d) { max_d=dis[v]; res=v; } pre[v]=u; que.push(v); vis[v]=1; } } } return res;}int flag[Maxn];bool check(int mid){ memset(dis,0,sizeof(dis)); memset(flag,0,sizeof(flag)); bfs(road[mid]); for(int i=1; i<=N; i++) { if(dis[i]<=mid) flag[i]=1; } memset(dis,0,sizeof(dis)); bfs(road[sum-mid-1]); for(int i=1; i<=N; i++) { if(dis[i]<=mid) flag[i]=1; } for(int i=1; i<=N; i++) { if(flag[i]==0) return false; } return true;}int main(){ int T,n,u,v,temp,s1,s2; cin>>T; while(T--) { scanf("%d",&n); N=n; init(); for(int i=1; i<n; i++) { scanf("%d%d",&u,&v); addedge(u,v,1); addedge(v,u,1); } memset(dis,0,sizeof(dis)); s1=bfs(1); memset(dis,0,sizeof(dis)); memset(pre,-1,sizeof(pre)); s2=bfs(s1); u=s2; sum=0; while(u!=-1) { road[sum++]=u; u=pre[u]; } int l,r,mid,ans[3]; l=0; r=sum; while(l<=r) { mid=(r+l)/2; if(check(mid)) { ans[0]=mid; ans[1]=road[mid]; ans[2]=road[sum-mid-1]; if(ans[1]==ans[2])///如果两个点是同一个点,随便把一个点换掉就行 { for(int i=0; i<sum; i++) if(ans[1]!=road[i]) { ans[2]=road[i]; break; } } r=mid-1; } else l=mid+1; } printf("%d %d %d\n",ans[0],ans[1],ans[2]); } return 0;}/**15101 22 33 44 55 66 74 88 99 10*/
- zoj3820 树直径上二分选点
- zoj3820(树的直径的应用)
- 2014牡丹江区域赛B(树的直径)ZOJ3820
- 求树的直径和中心(ZOJ3820)
- 二分+树上乱搞 zoj3820 Building Fire Stations
- ZOJ 3684 Destroy 树的直径+二分
- ZOJ 3820 (树的直径 + 二分)
- 二分+树的直径 [Sdoi2011]消防
- zoj 3820 Building Fire Stations (二分+树的直径)
- 2282: [Sdoi2011]消防 树的直径+二分答案
- bzoj 2282: [Sdoi2011]消防(树的直径+二分)
- 避难向导 树的直径 树上倍增 二分答案
- ZOJ 3826 Hierarchical Notation(2014 牡丹江 B,树的直径+二分)
- hdoj 4123 Bob’s Race 【树的直径 + RMQ】 【二分查询会超时】
- NKOJ 2650 (SDOI 2011) 消防(树的直径+DP+单调队列/二分答案)
- 2014-2015icpc 牡丹江 B.Building Fire Stations (二分+树的直径)
- bzoj3124 [Sdoi2013]直径 树的直径
- 【树的直径】
- MySQL数据库(主键、索引、外键、触发器...)
- java学习历程笔记心得
- Centos 7防火墙firewalld开放80端口
- HDU_6017_Girls love 233_(dp)(记忆化搜索)
- java构造函数使用方法总结
- zoj3820 树直径上二分选点
- 移动式除虫 SPFA
- C#中静态与非静态方法比较
- HttpClient使用代理IP
- struct与typedef struct
- 在Oracle 中使用CONNECT BY PRIOR START WITH 语句详解
- 全文检索Lucene(三)----查询,分词器,排序,过滤,高亮
- POJ3630(Trie树)
- maven镜像配置settings.xml