首页 > 代码库 > ZOJ-3820 Building Fire Stations 题解

ZOJ-3820 Building Fire Stations 题解

题目大意:

  一棵树,在其中找两个点,使得其他点到这两个的距离的较小值的最大值的最小值及其方案。

思路:

  首先显然一棵树的直径的中点到其他点的距离的最大值必定比其他点的小。

  那么感性思考一下就将一棵树的直径平分成两段,在找分成的两棵树的直径的中点。

  PS:dfs貌似要爆栈,用非递归或bfs。

代码:

 1 #include<cstdio>
 2 const int M=200005;
 3 int ed,cnt,fa[M],q[M],dep[M],v[M<<1],nex[M<<1],hea[M];
 4 bool vis[M];
 5 
 6 int read()
 7 {
 8     int x=0; char ch=getchar();
 9     while (ch<0 || ch>9) ch=getchar();
10     while (ch>=0 && ch<=9) x=(x<<1)+(x<<3)+ch-48,ch=getchar();
11     return x;
12 }
13 
14 void add(int x,int y) { v[++cnt]=y,nex[cnt]=hea[x],hea[x]=cnt; }
15 
16 void build(int s)
17 {
18     int h=0,t=1; fa[s]=0;
19     dep[q[1]=ed=s]=1;
20     while (h^t)
21     {
22         int x=q[++h],y,i;
23         for (i=hea[x];i;i=nex[i])
24             if (!vis[y=v[i]] && y^fa[x])
25             {
26                 dep[y]=dep[fa[q[++t]=y]=x]+1;
27                 if (dep[ed]<dep[y]) ed=y;
28             }
29     }
30 }
31 
32 void getdis(int x) { build(x); build(ed); }
33 
34 int main()
35 {
36     for (int T=read();T;--T)
37     {
38         int n=read(),ans,i,len,x,y,z;
39         for (cnt=i=0;i<=n;++i) hea[i]=0;
40         for (i=1;i<n;++i)
41         {
42             x=read(),y=read();
43             add(x,y),add(y,x);
44         }
45         getdis(1); len=dep[x=ed];
46         for (;dep[x]!=(len>>1)+1;x=fa[x]);
47         vis[x]=1; getdis(fa[x]); len=dep[y=ed];
48         for (;dep[y]!=(len>>1)+1;y=fa[y]);
49         ans=len>>1; vis[x]=0; vis[z=fa[x]]=1;
50         getdis(x); len=dep[ed]; vis[z]=0;
51         for (;dep[ed]!=(len>>1)+1;ed=fa[ed]);
52         len=len>>1; if (ans<len) ans=len;
53         printf("%d %d %d\n",ans,y,ed);
54     }
55     return 0;
56 }

 

ZOJ-3820 Building Fire Stations 题解