title: Minimum Transport Cost(floyd保存路径)
tags: [最短路径]
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
题意
从一个城市到另一个城市需要费用,这个费用由两部分组成,一部分是公路的费用一部分是经过某个城市需要付税,起点和终点不用付税。输出最少费用的那条路,如果有多条就输出字典序小的的那个。
分析
一开始没有认真读题,以为只是让求出最短路径就行,没有考虑到有多条最短路径。先是用的迪杰斯特拉算法,保存每一个点的前驱节点,以此来输出路径,这种方法当遇到多条最短路径是还需要找出这一条路径的所有的点与另一条路径所有的点,将他们构成一个字符串然后按照字典序来比较大小,这样就是很麻烦,所以在保存路路径是时如果能保存后继节点,这样的遇到两条最短路径时就能够直接比较大小。
对于弗洛伊德算法能较方便的保存后继节点。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define MAX1 1050
using namespace std;
int value[MAX1];
int road[MAX1][MAX1];
int path[MAX1][MAX1];
void init(int n)
{
for (int i=1; i<=n; i++ )
for (int j=1; j<=n; j++)
{
if (i==j)road[i][j]=0;
else road[i][j]=inf;
path[i][j]=j;//刚开始从i到j点的最优解就是直接从i到j,所以path[i][j]=j;
}
}
void floyd(int n)
{
for (int k=1; k<=n; k++)
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
{
if (i==j)continue;
if(road[i][k]==inf||road[k][j]==inf)continue;
int t=road[i][k]+road[k][j]+value[k];
if (road[i][j]>t)//经过k点使得i-->j的距离更短
{
road[i][j]=t;
path[i][j]=path[i][k];//所以此时的i--->j的最优解不再是j了而是 i--->k---->j;
}
else if (road[i][j]==t)
{
if (path[i][k]<path[i][j])//存在多条最短路径,比较字典序
path[i][j]=path[i][k];
}
}
}
int main()
{
int n;
while (scanf("%d",&n),n)
{
init(n);
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
{
scanf("%d",&road[i][j]);
if(road[i][j]==-1)road[i][j]=inf;
}
for (int i=1; i<=n; i++)
scanf("%d",&value[i]);
floyd(n);
int a,b;
while (scanf("%d%d",&a,&b))
{
if (a==-1&&b==-1)
break;
int u=a;
printf("From %d to %d :
",a,b);
printf("Path: %d",a);
while (a!=b)//
{
printf("-->%d",path[a][b]);
a=path[a][b];
}
printf("
");
printf("Total cost : %d
",road[u][b] );
}
}
return 0;
}
/**
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
5
0 -1 1 -1 1
-1 0 -1 1 1
1 -1 0 7 -1
-1 1 7 0 -1
1 1 -1 -1 0
1 1 1 1 1
3 4
0
*/