PAT甲级 1030 旅行计划 dijkstra算法求最短路并输出最短路径

原题链接

给定一张地图,包含 N 个城市,M 条高速公路。

城市之间都能相互连通。

每条高速公路的长度和走该条公路的花费都是已知的,高速公路都是双向的。

现在要从地图中的某个城市前往另一个城市。

请你确定最短路径,当最短路径不唯一时,请你选取花费最小的路径(保证唯一)。

输入格式
第一行包含四个整数 N,M,S,D,分别表示城市数量,公路数量,起点城市编号,终点城市编号。

城市编号从 0 到 N−1。

接下来 M 行,每行包含四个整数 a,b,c,d,表示城市 a 和城市 b 之间存在一条公路,长度为 c,花费为 d。

输出格式
共一行,首先输出从起点城市到终点城市的最短路径(花费最少的)经过的所有城市,然后输出最短路径的距离以及最小的花费。

数据范围
1≤N≤500,
1≤M≤600,
1≤c,d≤500
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
0 2 3 3 40

我的解法:

#include <bits/stdc++.h>
using namespace std;
const int N = 550;
int n, m, S, T;
int g[N][N]; // 两节点的边长
int pre[N]; // 为了遍历输出路径,存储最短路当前节点的上一节点
int dist[N]; // 从S 到任一点的最短路径
int cost[N]; // 从S 到任一点最短路花费,如果有多条最短路,则是花费最少的最短路花费
int c[N][N]; // 两节点的花费
bool st[N]; // 是否使用过
void dijkstra(){
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;
    for(int i = 0; i < n; i ++ ){
        int t = -1;
        for(int j = 0; j <= n - 1; j ++ ){
            if(!st[j] && (t == -1 || dist[j] < dist[t])){
                t = j;
            }
        }
        st[t] = true;
        for(int j = 0; j <= n - 1; j ++ ){
            if(dist[j] > g[t][j] + dist[t]){
                dist[j] = g[t][j] + dist[t];
                pre[j] = t;
                cost[j] = cost[t] + c[t][j];
            }
            else if(dist[j] == g[t][j] + dist[t] && cost[j] > cost[t] + c[t][j]){
                pre[j] = t;
                cost[j] = cost[t] + c[t][j];
            }
        }
    }
}
int main(){
    cin >> n >> m >> S >> T;
    memset(g, 0x3f, sizeof g);
    memset(c, 0x3f, sizeof c);
    while(m -- ){
        int a, b, cc, dd;
        cin >> a >> b >> cc >> dd;
        g[a][b] = g[b][a] = min(g[a][b], cc);
        c[a][b] = c[b][a] = min(c[a][b], dd);
    }
    dijkstra();
    vector <int> path;
    for(int i = T; i != S; i = pre[i] ){
        path.push_back(i);
    }
    cout << S;
    for(int i = path.size() - 1; i >= 0; i -- ){
        cout << ' ' << path[i];
    }
    cout << ' ' << dist[T] << ' ' << cost[T];
    return 0;
}

收获:

如何求出具体的最短路径,即输出最短路上的节点

用pre数组存取上一节点,遍历保存到vector里,最后再反向输出

    for(int i = T; i != S; i = pre[i] ){
         path.push_back(i);
    }

    cout << S;
    for(int i = path.size() - 1; i >= 0; i -- ){
        cout << ' ' << path[i];
    }

猜你喜欢

转载自blog.csdn.net/weixin_45660485/article/details/124935634