bzoj2237[NCPC2009]Flight Planning 结论题?
2237: [NCPC2009]Flight Planning
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 55 Solved: 27
[Submit][Status][Discuss]
Description
S航空公司在N座城市之间有N-1条航线,航线是双向的。任意两座城市都是可以互相到达的,但是可能需要在一些城市换乘不同的航线。
目前有人抱怨要到达有些城市需要换乘太多次,S航空公司为了缓解这一现状,决定取消目前的一条航线,添加另一条航线,在保证任意两座城市还是可以互相到达的前提下,使得两座城市之间需要乘坐的航线次数的最大值最小。
Input
第一行为一个整数N(4<=N<=2500),表示城市的个数。城市从1到N编号。
接下来N-1行,每行是一对整数a和b,表示一条连接a和b的航线(1<=a,b<=N)。
Output
输出仅一行,即航空公司进行调整后,任意两座城市之间需要乘坐的航班次数的最大值。
Sample Input
4
1 2
2 3
3 4
Sample Output
2
【样例解释】
取消3-4的航线,添加2-4的航线。
HINT
对于100%的数据,N<=2500。
题意:在一棵树上,你可以任意删除一条边再加上一条并使得这个图还是颗树,在此前提下,你要让树的直径最小,求最小直径
n^2是可以接受的
枚举每一条边,把它断开,形成两个联通块,对这两个联通块求直径l1 l2
那么ans=min(ans,max(l1,l2,(l1+1)/2+(l2+1)/2+1))
简单说明一下后面那一坨:
对于两棵树,要把它们连起来后是直径最小,肯定是链接两颗树直径的中点
用反证法可以证明这样更优:假设选择另外的点链接,那么直径两端(a , b)到它的距离的max(disa,disb) 不会比到中点的距离短
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #define N 2505 6 using namespace std; 7 int n,tot=1,l1,l2,hd[N],dis[N],x[N],y[N],ban[N<<1]; 8 struct edge{int u,v,next;}e[N<<1]; 9 void adde(int u,int v){ 10 e[++tot].v=v; 11 e[tot].u=u; 12 e[tot].next=hd[u]; 13 hd[u]=tot; 14 } 15 void dfs(int u,int fa){ 16 for(int i=hd[u];i;i=e[i].next){ 17 int v=e[i].v; 18 if(v==fa||ban[i])continue; 19 dis[v]=dis[u]+1; 20 dfs(v,u); 21 } 22 } 23 int getlen(int x){ 24 int t1,t2; 25 memset(dis,0,sizeof(dis)); 26 dfs(x,0);t1=x; 27 for(int i=1;i<=n;i++) 28 if(dis[i]>dis[t1])t1=i; 29 memset(dis,0,sizeof(dis)); 30 dfs(t1,0);t2=t1; 31 for(int i=1;i<=n;i++) 32 if(dis[i]>dis[t2])t2=i; 33 return dis[t2]; 34 } 35 int main(){ 36 scanf("%d",&n); 37 for(int i=1;i<n;i++){ 38 int u,v; 39 scanf("%d%d",&u,&v); 40 adde(u,v);adde(v,u); 41 }int ans=1<<30; 42 for(int i=2;i<=tot;i+=2){ 43 ban[i]=ban[i^1]=1; 44 l1=getlen(e[i].u); 45 l2=getlen(e[i].v); 46 ans=min(ans,max(l1,max(l2,(l1+1)/2+(l2+1)/2+1))); 47 ban[i]=ban[i^1]=0; 48 }printf("%d",ans); 49 return 0; 50 }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。