[毁灭世界的01]城市交通

【描述】

某城市有N1<=N<=50)个街区,某些街区由公共汽车线路相连,如在图1中,街区12有一条公共汽车线路相连,且由街区1至街区2的时间为34分钟。由于街区与街区之间的距离较近,与等车时间相比可忽略不记,所以这个时间为两趟公共汽车的间隔时间,即平均的等车时间。

由街区1至街区5的最快走法为1-3-5,总时间为44分钟。

现在市政府为了提高城市交通质量,决定加开M(1<=M<=10)条公共汽车线路。若在某两个街区A,B之间加开线路(前提是AB之间必须已有线路),则从AB的旅行时间缩小为原来的一半(距离未变,只是等车的时间缩短了一半)。例如,若在12之间加开一条线路,则时间变为17分钟,加开两条线路,时间变为8.5分钟,以此类推。所有的线路都是环路,即如果由12的时间变为17分钟,则由21的时间也变为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;
}

 

 





posted @ 2010-09-13 18:02  Sephiroth.L.  阅读(270)  评论(0编辑  收藏  举报