【描述】
某城市有N(1<=N<=50)个街区,某些街区由公共汽车线路相连,如在图1中,街区1,2有一条公共汽车线路相连,且由街区1至街区2的时间为34分钟。由于街区与街区之间的距离较近,与等车时间相比可忽略不记,所以这个时间为两趟公共汽车的间隔时间,即平均的等车时间。
由街区1至街区5的最快走法为1-3-5,总时间为44分钟。
现在市政府为了提高城市交通质量,决定加开M(1<=M<=10)条公共汽车线路。若在某两个街区A,B之间加开线路(前提是A、B之间必须已有线路),则从A到B的旅行时间缩小为原来的一半(距离未变,只是等车的时间缩短了一半)。例如,若在1,2之间加开一条线路,则时间变为17分钟,加开两条线路,时间变为8.5分钟,以此类推。所有的线路都是环路,即如果由1至2的时间变为17分钟,则由2至1的时间也变为17分钟。
求加开某些线路,能使由城市1至城市N的时间最少。例如,在图1中,如果M=2,则改变1-3,3-5的线路,总的时间可以减少为22分钟。
【输入格式】
输入文件名为City.Inp。
第一行为城市数N与加开线路数M。
第二行至第N+1行,每行为N个实数,第I+1行第J列表示由城市I到城市J的时间。
如果时间为0,则城市I不可能到城市J。
注意:输入数据中,从城市1到城市N至少有一条路线。
【输出格式】
输出文件名为City.Out.
第一行为由城市1到城市N的最小时间X(保留小数点后两位)。
第二行至第M+1行为更改的线路。每行由两个整数(x,y)构成。表示将城市x与城市y之间增加一条线路。
【样例输入】
52
034 24 0 0
340 10 12 0
2410 0 16 20
012 16 0 30
00 20 30 0
【样例输出】
22.00
13
35
【分析】
乍一看…………没感觉。完全不知道怎么解决。
开始想图结构的经典算法。当想到floyd的时候,突然发现,可以将floyd变化一下,然后就有点资源分配的感觉。于是一个算法出来了。第一次提交,50分。小看了下题解,和自己想的一样。但是就是不知道哪里错了。然后,想了一节课。发现动归过程的g应该从0开始,因为不加汽车也是可以有点之间距离的更新的。动归数组f[i][j][k]表示从i到j共加k条所能达到的最短路。方程很好理解。输出顺序题目没说,我就用最简单的方法输出了。恩,AC。
#include <stdio.h> #define maxn 60 #define maxm 20 #define maxint 1000000000 double f[maxn][maxn][maxm]; int from[maxn][maxn][maxm][2]; int n,m; void print(int a,int b,int c) { if (!from[a][b][c][0]) for (int i=1;i<=c;++i) printf("%d %d",a,b); else { print(a,from[a][b][c][0],from[a][b][c][1]); print(from[a][b][c][0],b,c-from[a][b][c][1]); } } int main() { freopen("city.in","r",stdin); freopen("city.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) { scanf("%lf",&f[i][j][0]); if (!f[i][j][0]) f[i][j][0]=maxint; } for (int g=1;g<=m;++g) for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) if (f[i][j][0]<maxint) f[i][j][g]=f[i][j][g-1]/2; else f[i][j][g]=maxint; for (int g=0;g<=m;++g) for (int k=1;k<=n;++k) for (int i=1;i<=n;++i) if (i!=k) for (int j=1;j<=n;++j) if ((i!=j)&&(j!=k)) for (int t=0;t<=g;++t) if (f[i][k][t]+f[k][j][g-t]<f[i][j][g]) { from[i][j][g][0]=k; from[i][j][g][1]=t; f[i][j][g]=f[i][k][t]+f[k][j][g-t]; } printf("%.2lf\n",f[1][n][m]); print(1,n,m); return 0; }