• 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;    
    }
  • 相关阅读:
    【推广】+发送短信
    【Linux】+文件操作
    【CRT】+文件上传与下载
    【Java】+查看调用关系
    【博客园】+设置
    【Java】+http
    【Postman】
    【Java】+模拟浏览器操作
    【Java】+快速打印数组
    【Java】+字符串
  • 原文地址:https://www.cnblogs.com/Lyush/p/2948872.html
Copyright © 2020-2023  润新知