题目链接
题目大意:给你一个邻接矩阵和每个点的权值,问你任意两点的最短路的花费以及路径。
这个题途中经过某个点收费很好处理,只要在松弛的时候加上中间点的权值即可,但是打印路径就有些麻烦了。因为是多源最短路问题,所以我们不能像单源最短路那样用一维的数组来存前驱/后驱来打印路径了。
我们可以用一个二维的数组来存每个路径的后驱,比如我们要计算1到3的最短路,而路径是1->5->4->3,那么我们只要知道1->3的下一步、5->3的下一步、4->3的下一步即可,因为要求字典序最小的路径,所以如果
路径长度相等的话需要选靠前面的最小的点作为后驱。
const int maxn = 1e3+10;
int n, p[maxn][maxn], cost[maxn], g[maxn][maxn];
void floyd() {
for (int k = 1; k<=n; ++k)
for (int i = 1; i<=n; ++i)
if (g[i][k]!=INF)
for (int j = 1; j<=n; ++j) {
int tmp = g[i][k]+g[k][j]+cost[k];
if (g[i][j]>tmp || (g[i][j]==tmp && p[i][j]>p[i][k])) {
p[i][j] = p[i][k];
g[i][j] = g[i][k]+g[k][j]+cost[k];
}
}
}
void print_path(int a, int b) {
printf("From %d to %d :
", a, b);
printf("Path: %d", a);
int next = a;
while(next!=b) {
next = p[next][b];
printf("-->%d", next);
}
putchar(endl);
}
int main(void) {
while(~scanf("%d", &n)) {
for (int i = 1; i<=n; ++i)
for (int j = 1; j<=n; ++j) {
scanf("%d", &g[i][j]);
if (g[i][j]==-1) g[i][j] = INF;
else p[i][j] = j;
}
for (int i = 1; i<=n; ++i) scanf("%d", &cost[i]);
floyd();
int a, b;
while(~scanf("%d%d", &a, &b) && (a!=-1&&b!=-1)) {
print_path(a, b);
printf("Total cost : %d
", g[a][b]);
}
}
return 0;
}