【图论】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.
	

反思

先确定枚举的算法,由于树这种特殊的结构,可将父亲的状态转移给儿子。这样便能出色的解决问题,特别是神搜的算法还需加强。注意边界状态的初值。

posted @ 2011-07-20 17:22  liukee  阅读(302)  评论(0编辑  收藏  举报