PAT甲级-1030 Travel Plan

题目

题目大意

给出城市的个数n,路的数目m,起点s和终点d。接下来以c1 c2 d cost的形式给出两座城市之间的距离和花费。要求计算从起点到终点的最短路径,如果有多条最短路径,则输出花费最小的最短路径。然后再输出最短路径的总距离和总花费。

思路

迪杰斯特拉求最短路径。dist数组记录最短路径的长度,visited数组标志节点是否被激活(无需temp数组)。要求输出最短路径,就需要一个数组来记录节点值,比较常见的做法就是构建一维数组path记录节点的前驱节点值,最后输出的时候递归回溯path数组即可。还需要minCost数组,记录每个节点的最小花费,便于在多个最短路径中选出最小花费的路径。

代码

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

int n, m, s, d;
int g[501][501] = {0};  // 图
int cost[501][501] = {0};  // 记录花费
vector<int> dist;  // 记录最短路径
vector<int> minCost;  // 记录最小花费
vector<int> path;  // 记录最短路径的前驱节点

void dijie() {
    bool visited[501] = {false};
    dist[s] = 0;
    minCost[s] = 0;

    for (int cnt = 0; cnt < n; cnt++) {
        int now = -1;  // 要激活的节点
        int minDist = INT_MAX;
        // 寻找未访问的节点中距离最小的节点
        for (int i = 0; i < n; i++) {
            if (!visited[i] && dist[i] < minDist) {
                minDist = dist[i];
                now = i;
            }
        }

        if (now == -1) return;  // 如果找不到,说明所有节点都已访问,退出
        visited[now] = true;  // 激活节点 now

        // 更新从 now 到其他节点的距离和花费
        for (int i = 0; i < n; i++) {
            if (!visited[i] && g[now][i] < INT_MAX) {
                if (dist[i] > dist[now] + g[now][i]) {
                    dist[i] = dist[now] + g[now][i];
                    minCost[i] = minCost[now] + cost[now][i];
                    path[i] = now;  // 更新i的前驱节点
                } else if (dist[i] == dist[now] + g[now][i]) {
                    if (minCost[i] > minCost[now] + cost[now][i]) {
                        minCost[i] = minCost[now] + cost[now][i];
                        path[i] = now;
                    } else if (minCost[i] == minCost[now] + cost[now][i]) {
                        path[i] = now;
                    }
                }
            }
        }
    }
}

void printPath(int node) {
    if (node == s) {
        cout << node << " ";
        return;
    }  // 如果是起点,完成输出并返回
    printPath(path[node]);  // 回溯前驱节点
    cout << node << " ";  // 输出当前节点
}  // 递归输出路径,回溯path数组

int main() {
    cin >> n >> m >> s >> d;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            g[i][j] = (i == j) ? 0 : INT_MAX;
        }
    }  // 初始化图
    for (int i = 0; i < m; i++) {
        int c1, c2, dist, weight;
        cin >> c1 >> c2 >> dist >> weight;
        g[c1][c2] = g[c2][c1] = dist;
        cost[c1][c2] = cost[c2][c1] = weight;
    }  // 得到图和花费矩阵

    dist.resize(n, INT_MAX);
    minCost.resize(n, INT_MAX);
    path.resize(n);

    dijie();
    printPath(d);  // 输出从 s 到 d 的路径
    cout << dist[d] << " " << minCost[d] << endl;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_74092648/article/details/143169279