ZOJ1456 Minimum Transport Cost 最短路floyd路径输出

这题难就难再要字典序输出,要是单单floyd的话,无法保证最后得到的路径字典序最小,一个简单的反例就是如果6 5 7 8 9和6 8 1 2 9以及6 10 1 2 9同时是6-9的最短路的话,如果忽略相等情况下的更新,6 8之间是不会被7作为中间节点而更新的,但是不忽略的话,又可能被中间比较大的节点更新了。所以直接floyd(采用path[i][j] = k表示i到j通过k点的方式还原路径)是不满足题意的。因此这里采用另外一种记录路径的方式,path[i][j]表示从i到j的第二个元素编号,那么由于仅仅只记录了第二个元素,因此当距离相等的时候,我们就只需要考虑新的“第二个元素”是否更优。这样可以避免将这个路径进行输出比较,如果距离相等,第二个元素相等,那么最后还原出来的路径就是一致的,无需更新。

代码如下:

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

/*
    相比于其他的最短路,这里只是多了一个节点上的信息 
*/
int N;
int G[1005][1005]; // 由于题目中并没有说清楚数据范围,因此我们可以假设最大的内存 
int path[1005][1005];  // 记忆路径 
int dis[1005];   // 表示距离
int add[1005];   // 表示额外的节点附加值

void floyd() {
    int reca[1005], recb[1005], idxa, idxb;
    for (int i = 1; i <= N; ++i) {
        for (int j = 1; j <= N; ++j) {
            path[i][j] = j;    
        } // path[i][j]记录的是从i到j这条路的第二个元素
    }
    for (int k = 1; k <= N; ++k) {
        for (int i = 1; i <= N; ++i) {
            if (i == k || G[i][k] == -1) continue;
            for (int j = 1; j <= N; ++j) {
                if (j == k || G[k][i] == -1) continue;
                if (G[i][k] != -1 && G[k][j] != -1) {
                    if(G[i][j] > G[i][k] + G[k][j] || G[i][j] == -1) {
                        G[i][j] = G[i][k] + G[k][j];
                        path[i][j] = path[i][k];
                    } else if (G[i][j] == G[i][k] + G[k][j]) {
                        if (path[i][j] > path[i][k]) { 
                        // 由于记录的直接是第二个元素,所以只有当这个第二个元素小于已知值时才更新 
                            path[i][j] = path[i][k];
                        }
                    }
                }
            }    
        }    
    }
}

void display(int x, int y) {
    if (x != y) {
        printf("-->%d", path[x][y]);
        display(path[x][y], y);
    }
}

int main() {
    while (cin >> N, N) {
        memset(path, 0xff, sizeof (path));
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                scanf("%d", &G[i][j]);
                // 对整个图进行一个读取
            }
        }
        for (int i = 1; i <= N; ++i) {
            scanf("%d", &add[i]);
        }
        for (int i = 1; i <= N; ++i) {
            for (int j = 1; j <= N; ++j) {
                if (i == j || G[i][j] == -1) continue;
                else G[i][j] += add[j];
            } // 将节点信息直接附加在边上,这样就是起始点没有加上节点值
        }
        floyd();
        int a, b, first;
        while (scanf("%d %d", &a, &b), a!=-1 && b!=-1) {
            first = 1;
            printf("From %d to %d :\n", a, b);
            printf("Path: %d", a);
            display(a, b);
            puts("");
            printf("Total cost : %d\n\n", a!=b ? G[a][b]-add[b] : 0);
        }
    }
    return 0;    
}
原文地址:https://www.cnblogs.com/Lyush/p/2948872.html