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]);
}
}
}