Minimum Transport Cost (Folyd算法求最短路,记录路径)

These are N cities in Spring country. Between each pair of cities there may be one transportation track or none. Now there is some cargo that should be delivered from one city to another. The transportation fee consists of two parts: 
The cost of the transportation on the path between these cities, and 

a certain tax which will be charged whenever any cargo passing through one city, except for the source and the destination cities. 

You must write a program to find the route which has the minimum cost. 

Input

First is N, number of cities. N = 0 indicates the end of input. 

The data of path cost, city tax, source and destination cities are given in the input, which is of the form: 

a11 a12 ... a1N 
a21 a22 ... a2N 
............... 
aN1 aN2 ... aNN 
b1 b2 ... bN 

c d 
e f 
... 
g h 

where aij is the transport cost from city i to city j, aij = -1 indicates there is no direct path between city i and city j. bi represents the tax of passing through city i. And the cargo is to be delivered from city c to city d, city e to city f, ..., and g = h = -1. You must output the sequence of cities passed by and the total cost which is of the form: 

Output

From c to d : 
Path: c-->c1-->......-->ck-->d 
Total cost : ...... 
...... 

From e to f : 
Path: e-->e1-->..........-->ek-->f 
Total cost : ...... 

Note: if there are more minimal paths, output the lexically smallest one. Print a blank line after each test case. 
 

Sample Input

5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
-1 -1
0

Sample Output

From 1 to 3 :
Path: 1-->5-->4-->3
Total cost : 21

From 3 to 5 :
Path: 3-->4-->5
Total cost : 16

From 2 to 4 :
Path: 2-->1-->5-->4
Total cost : 17

题意:在n个城市之间要运送一些货物,为了各个城市之间的运输费(邻接图),同时除起始城市和目标城市外货物经过其他城市都要收取相应的税费,图下给了每个城市的税费。接下来的多组数据包括一个起点,一个终点。求最小的花费,如果有多条路径每组条件,输出字典序最小的路径。输入-1,-1时结束本组测试数据。

思路:由于是求多个城市之间的最小花费,我们就可以将Folyd算法稍加变形就可以得到最小的花费了,但输出路径就比较让人头疼了,刚开始我是用string来记录结果wa了。后来才发现我记录只是一条路径,并不是字典序最小的路径。后来用了一个结构体(完全可以用一个二维数组)来记录任意两点之间通过哪些中间点来松弛,最主要的是如果两点之间先前已经算到的花费和通过新的点松弛后的花费一样,一定要比较一下两者的顶点坐标了,确保所得到的路径字典序最小。最后通过递归输出路径。

代码如下:

#include<cstdio>
#include<cstring>
#include<string>
#define inf 0x3f3f3f3f
using namespace std;
struct node
{
    int x;
} list[200][200];
int map[220][220],num[220];
void print(int a,int b) //递归输出路径
{
    if(a==b)            //终点
    {
        printf("%d\n",b);
        return;
    }
    printf("%d-->",a);  //起点,或者中间点
    print(list[a][b].x,b);//因为list[a][b].x记录的是通过a到b的中间点,到此中间点到终点可能还有中间点
}
int main()
{
    int n;
    while(~scanf("%d",&n)&&n)
    {
        int l;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=n; j++)
            {
                scanf("%d",&l);
                if(l==-1)         //-1为没有路径  赋予无穷大更好处理
                    l=inf;
                map[i][j]=l;      //建图
                list[i][j].x=j;    //把路径初始化,i->j没有中间点,所有就是j
            }
        for(int i=1; i<=n; i++)  //每个城市的税费
            scanf("%d",&num[i]);
        for(int k=1; k<=n; k++)  //枚举每个中间点
        {
            for(int i=1; i<=n; i++)
            {
                for(int j=1; j<=n; j++)
                {
                    if(map[i][j]>map[i][k]+map[k][j]+num[k]) //因为有税费所以要加上税费来维护
                    {
                        map[i][j]=map[i][k]+map[k][j]+num[k];
                        list[i][j].x=list[i][k].x;        //i->j 先经过 k 再转到 j
                    }
                    else if(map[i][j]==map[i][k]+map[k][j]+num[k])  //花费一样,要最小的点,这样才能保证字典序最小
                    {
                        if(list[i][j].x>list[i][k].x)
                        {
                            map[i][j]=map[i][k]+map[k][j]+num[k];
                            list[i][j].x=list[i][k].x;
                        }
                    }
                }
            }
        }
        int a,b;
        while(scanf("%d%d",&a,&b))  //输入起点,终点
        {

            if(a==-1&&b==-1)
                break;
            printf("From %d to %d :\nPath: ",a,b);
            print(a,b);  //递归输出路径
            printf("Total cost : %d\n\n",map[a][b]);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值