1、城市交通某城市有 n(1n50)个街区,某些街区由公共汽车线路相连,如在下图中,街区1,2 有一条公共汽车线路相连,且由街区 1至街区 2的时间为 34分钟。由于街区与街区之间的距离较近,与等车时间相比可忽略不记,所以这个时间为两趟公共汽车的间隔时间,即平均的等车时间。由街区 1至街区 5的最快走法为 1-3-5,总时间为 44分钟。现在市政府为了提高城市交通质量,决定加开 m(1m10)条公共汽车线路。若在某两个街区 a,b 之间加开线路(前提是 a、b 之间必须已有线路) ,则从 a到 b的旅行时间缩小为原来的一半(距离未变,只是等车的时间缩短了一半) 。例如,若在 1,2 之间加开一条线
2、路,则时间变为 17分钟,加开两条线路,时间变为 8.5分钟,以此类推。所有的线路都是环路即无向,即如果由 1至 2的时间变为 17分钟,则由 2至 1的时间也变为 17分钟。求加开某些线路,能使由城市 1至城市 n的时间最少。例如,在上图中,如果 m=2,则改变 1-3,3-5 的线路,总的时间可以减少为 22分钟。输入:第一行为城市数 n与加开线路数 m。第二行至第 n+1行,每行为 n个实数,第 i+1行第 j列表示由城市 i到城市 j的时间。如果时间为 0,则城市 i不可能到城市 j。注意:输入数据中,从城市 1到城市 n至少有一条路线。输出:第一行为由城市 1到城市 n的最小时间 X
3、(保留小数点后两位) 。第二行至第 m+1行为更改的线路。每行由两个整数(x,y)构成。表示将城市 x与城市y之间增加一条线路。分析:城市交通问题的图论模型很简单。如果只考虑从城市 1 到城市 n 的最少时间,那么,这个问题就是一道经典的最短路径问题。因此,这个问题乍看上去,就给人一种熟悉的感觉。而实质呢?问题的“变数”在于市政府的改革措施很奇特(每加一条公共汽车路线,两个街区之间的旅行时间就缩短为原来的一半) ,这就弄得人不知所措。是否是关键路径的问题?显然,这个改革不能分步执行,即它不具有“贪心法”的要求,而如果采用搜索的方法,时间效率会很低。那么该如何解决呢?还是采用 Floyd-War
4、shall 的算法思想。在计算增加 m 条边的最优解(使最短路下降最快)的过程中,我们同样可以发现:1、将道路 a-b 上增加的 m 条边可以分为如下两个问题(如果 k 是最短路上的一点)1. 求 a-k 增加 t 条边;2. 求 k-b 增加 m-t 条边。t 可以取从 0 至 m 的任意值。问题 a-b 增加 m 条边的最优解取决与这两个子问题的最优解。2、在求 m 条边的过程中,始终只与增加 t 条边与增加 m-t 条边的子问题发生联系。以上两个特点即为“无后效性”与“最优子问题” 。所以, “城市交通”问题可采用动态程序设计方法。设vala,b,m 的值为增加 m 条线路后城市 a 到
5、城市 b 的最短路长。其中 vala,b,0的值为原交通图中边城市 a 至城市 b 的最短路,可以直接使用 floyd 算法计算;vala,b,m=minvala,k,t+valk,b,m-t(其中 t 为从 0 到 m 中的一个数,k 为a 到 b 中间的一点 )在两条道路增加的边数确定的条件下,采用 Floyd 算法计算最优解。所以这个问题实质上是一个双重动态程序设计问题。具体算法如下:直接使用 floyd 算法计算 vala,b,0(1an,1bn) ;for g1 to m do 按照新增加的边数 g 划分阶段begin对任一对城市(i,j)来说,(i,j)的边权减半;vali,j,g
6、= (i,j)的边权;for k1 to n do 枚举中间城市for i1 to n do 枚举经由城市 k 的所有城市对(ikj)for j1 to n do beginvali,j,g= ; 计算状态,),mi0tkjvaltkilgt 转移方程vali,j,g=minvali,j ,g ,vali,k,0+valk,j ,g valk,j,g0,valk ,j,0+vali,k,gvali ,k,g0 ;End;forend;for说明:这个问题的 val 数组的初始值与上一个 Floyd 算法不一样,初始值均为maxint。这个算法的时间复杂度为 W(n3*m2),约为 W(n5),
7、还是一个多项式级的算法。值得注意的是, 程序还要求可打印出增加的边,由于问题规模大,存储也需要一些技巧,这些小问题的解决请参看程序样例Constbig=1000000; 极大值Typemaps=array150,150 of Real; 地图类型Varmap:maps; 城市交通图Val:array010 of maps; Valki,j加入 k 条边后城市 i 和城市 j的最短路长Way:array010,150,150 ,12 of byte;最优结果记录表。 wayp,i,j存储 ij 的路径上新增 p 条线路的最佳方案。其中中间城市为 wayp,i ,j,2,ik 的路径上新增的线路数
8、为 wayp,i,j,1条n,m:integer; 城市数和加开的线路数Procedure init; 初始化过程,输入数据Vari,j:integer;beginReadln(n,m); 读城市数和加开的线路数new(map); 为城市交通图申请内存for i1 to n do 读城市交通图beginfor j1 to n do read(mapi,j) ;readln;end;forend;initProcedure main; 应用动态程序设计方法求解Vari,j,k,p,q:integer;R:real;beginR1;fillchar(way,sizeof(way),0); 最优结果
9、记录表初始化new(Val0); 通过 floyd-Warshall 算法计算新增线路前任两个顶点的最短路val0 map;for k1 to n dofor i1 to n doif val0i,k0 thenfor j1 to n doif (Val0k,j0) and (iVal0i,k+Val0k ,j) thenbeginVal0i,j Val0i ,k+Val0k ,j;Way0i,j, 1 0;Way0i,j, 2 k;end;thenfor p1 to m do 按照新增加的线路数 p 划分阶段beginfor i1 to n do 计算每条边在新增第 p 条线路后的距离for
10、 j1 to n domapi,j mapi,j/2;new(valp); 增加 P 条边后的最优距离列表初始化Valp map;for k1 to n do 枚举中间城市for i1 to n do 枚举经由城市 k 的所有城市对(ikj)if Val0i,k0 thenfor j1 to n doif (Val0k,j0) and (iValqi ,k+Valp-qk,j) thenbegin 若当前分解方案最优,则记下Valpi,j Valqi ,k+Valp-qk ,j;wayp,i ,j,1 q; 存储 ij 的路径上新增 p 条线路的最佳方案。其中中间城市为 wayp,i ,j,2
11、,ik 的路径上新增 wayp,i,j ,1 条线路wayp,i ,j,2 k;end;thenif Valpk,j0 then 若最优方案是城市 k 到城市 j 新增 p 条线if (valpi,j=0) or (Valpi,jVal0i,k+Valpk,j) thenbegin 若加入原线路(i,k)可使得 ij 的路径方案最优,则记下Valpi,j Val0i , k+Valpk,j;wayp,i ,j,1 0;wayp,i ,j,2 k;end;thenif Valpi,k0 then 若最优方案是城市 i 到城市 k 新增 p 条线if (valpi,j=0) or (Valpi,j
12、Valpi,k+Val0k,j) thenbegin 若加入原线路(k,j)可使得 ij 的路径方案最优,则记下Valpi,j Valpi , k+Val0k,j;wayp,i ,j,1 p;wayp,i ,j,2 k;End;thenEnd;thenEnd;forEnd;mainProcedure Print; 通过二分法输出结果Procedure Pr(l,r ,k:integer); 递归输出城市 l 至城市 r 间新增 k 条线路的最佳方案Vari:integer;beginif wayk,l,r,2=0 then 若城市 l 至城市 r 间没有中间城市,则输出 k条(l,r)begi
13、nfor i1 to k do writeln(, ,r);endthenElse beginpr(l,wayk ,l,r,2 ,wayk ,l,r,1); 递归输出城市 l 至城市wayk, l,r ,2间新增 wayk,l ,r,1 条线路的最佳方案pr(wayk,l ,r ,2,r ,k-wayk ,l,r ,1); 递归输出城市wayk, l,r ,2至城市 r 间新增 k-wayk,l ,r ,1条线路的最佳方案 end;elseend;prbeginwriteln(Valm1,n:0:2); 输出城市 l 至城市 n 的最小时间Pr(1,n,m); 输出城市 l 至城市 n 间新增 m 条线路的最佳方案end; Print begin 主过程init; 输入数据main; 求解Print; 输出数据End.总结:本题是双重动态程序设计的典型题,很复杂。个人认为,此题可以用求关键路径的方法,先找出一条关键路径,然后对其经过顶点进行排序,由大到小取 m 个。但此思路的正确性未得到验证,有待验证。