。问题
【题目描述】
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.
反思
先确定枚举的算法,由于树这种特殊的结构,可将父亲的状态转移给儿子。这样便能出色的解决问题,特别是神搜的算法还需加强。注意边界状态的初值。