【图论】Flight
。问题
【题目描述】
S航空公司在N座城市之间有N-1条航线,航线是双向的。任意两座城市都是可以互相到达的,但是可能需要在一些城市换乘不同的航线。
目前有人抱怨要到达有些城市需要换乘太多次,S航空公司为了缓解这一现状,决定取消目前的一条航线,添加另一条航线,在保证任意两座城市还是可以互相到达的前提下,使得两座城市之间需要乘坐的航线次数的最大值最小。
【输入格式】
第一行为一个整数N(4<=N<=2500),表示城市的个数。城市从1到N编号。
接下来N-1行,每行是一对整数a和b,表示一条连接a和b的航线(1<=a,b<=N)。
【输出格式】
输出仅一行,即航空公司进行调整后,任意两座城市之间需要乘坐的航班次数的最大值。
【样例】
Flight.in
4
1 2
2 3
3 4
Flight.out
2
【样例解释】
取消3-4的航线,添加2-4的航线。
【数据范围】
对于20%的数据,N<=15;
对于50%的数据,N<=200;
对于100%的数据,N<=2500。
分析
题目给出的是一棵树,就是要在树上删掉一条边再加一条边,使得最长的两点间的路径最短。
枚举删除的边v(i,j)
原先的树就变成了两棵分别为i,j为根的子树。这是,如果要加边,使得最大的最短,那么加边的位置就是确定的。假设我们找到i,j为根的子树的最长路径分别为ans1,ans2,那么我们现在加上边一定是在i,j两棵子树的中间加,使得新产生的路径尽量小,那么新产生的路径的最长的值就是 ans1 div 2+ans2 div 2+1
只需要在三者中去最大即可。再在所有删边情况中去最小。
递归搜索一棵一i为根的子树中的最长路径,dfs(x,y)表示:x为根不能走到y节点。f[i]表示以i为根的子树的通过i的最长路径,g[i]表示通过i的次长路径。则通过i能走出的最长路径为f[i]+g[i].每更新一个i的值,就和已有的最优值比较。
code
program liukeke; var a:array[0..2500,0..2500] of longint; f,g:array[0..2500] of longint; v:array[0..2500] of boolean; n,i,j,ans1,ans2,temp,ans,ans3,now,x,y:longint; procedure init; var i,x,y:longint; begin readln(n); for i:=1 to n-1 do begin readln(x,y); inc(a[x,0]);a[x,a[x,0]]:=y; inc(a[y,0]);a[y,a[y,0]]:=x; end; end; procedure dfs(x,y:longint); var i,son:longint; begin v[x]:=true; f[x]:=-1; g[x]:=-1; for i:=1 to a[x,0] do if (a[x,i]<>y)and(not v[a[x,i]])then begin son:=a[x,i]; dfs(son,y); if f[son]>f[x] then begin g[x]:=f[x]; f[x]:=f[son]; end else if f[son]>g[x] then g[x]:=f[son]; end; inc(f[x]); inc(g[x]); if f[x]+g[x]>temp then temp:=f[x]+g[x]; end; function max(a,b,c:longint):longint; begin max:=a; if b>max then max:=b; if c>max then max:=c; end; function up(x:longint):longint; begin if x mod 2=0 then exit(x div 2) else exit(x div 2+1); end; begin assign(input,'flight.in');reset(input); assign(output,'flight.out');rewrite(output); init; ans:=maxlongint; for i:=1 to n do for j:=1 to a[i,0] do if a[i,j]>i then begin fillchar(v,sizeof(v),0); x:=i; y:=a[i,j]; temp:=0; dfs(x,y); ans1:=temp; temp:=0; dfs(y,x); ans2:=temp; ans3:=up(ans1)+up(ans2)+1; now:=max(ans1,ans2,ans3); if now<ans then ans:=now; end; writeln(ans); close(input);close(output); end.
反思
先确定枚举的算法,由于树这种特殊的结构,可将父亲的状态转移给儿子。这样便能出色的解决问题,特别是神搜的算法还需加强。注意边界状态的初值。