📜  Dijkstra 最短路径算法中的打印路径(1)

📅  最后修改于: 2023-12-03 15:14:41.144000             🧑  作者: Mango

Dijkstra 最短路径算法中的打印路径

Dijkstra 最短路径算法是一种经典的图论算法,用于寻找图中两个节点之间的最短路径。在实现 Dijkstra 算法时,我们需要记录每个节点到源节点的距离和前驱节点,以便在计算出最短路径后能够打印出路径。

实现过程

在实现 Dijkstra 算法时,我们需要使用一个队列保存当前未确定的节点,每次从队列中选择距离源节点最近的节点进行计算。如果该节点到源节点的距离加上该节点到下一个节点的距离小于下一个节点到源节点的距离,则更新下一个节点的距离和前驱节点。直到队列为空或者已经计算出终点节点的最短路径为止。

下面是 Dijkstra 算法的 C++ 代码实现:

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

const int MAXN = 100;    // 最大节点数
const int INF = 0x3f3f3f3f;  // 无穷大

int n, m;   // 节点数和边数
int s, t;   // 源节点和终点节点

struct Edge   // 边的结构体
{
    int v, w;   // v表示边的终点,w表示边的权值
    Edge() {}
    Edge(int v, int w) : v(v), w(w) {}
};

vector<Edge> G[MAXN];   // 图的邻接表存储形式

void dijkstra()   // Dijkstra算法
{
    int d[MAXN], pre[MAXN], vis[MAXN];  // d数组表示源节点到i节点的最短距离,pre数组表示i节点的前驱节点,vis数组表示i节点是否已访问过
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq;  // 小根堆

    memset(d, INF, sizeof(d));   // 初始化d数组
    memset(pre, -1, sizeof(pre));  // 初始化pre数组
    memset(vis, 0, sizeof(vis));  // 初始化vis数组

    d[s] = 0;   // 源节点到自身的距离为0
    pq.push(make_pair(0, s));

    while (!pq.empty())
    {
        int u = pq.top().second;
        pq.pop();

        if (vis[u]) continue;   // 如果已经访问过,则跳过

        vis[u] = 1;

        for (int i = 0; i < G[u].size(); i++)   // 遍历u节点的所有邻居
        {
            int v = G[u][i].v, w = G[u][i].w;

            if (d[u] + w < d[v])   // 如果经过u可以到达v的距离比已有的更短,则更新d数组和pre数组
            {
                d[v] = d[u] + w;
                pre[v] = u;
                pq.push(make_pair(d[v], v));
            }
        }
    }

    if (d[t] == INF)   // 没有找到从s到t的路径
    {
        cout << "There is no path from " << s << " to " << t << "." << endl;
    }
    else   // 打印相应路径
    {
        vector<int> path;
        for (int i = t; i != -1; i = pre[i]) path.push_back(i);
        reverse(path.begin(), path.end());
        cout << "Shortest Path from " << s << " to " << t << ": ";
        for (int i = 0; i < path.size(); i++) cout << path[i] << " ";
        cout << endl;
    }
}

int main()
{
    cin >> n >> m >> s >> t;

    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        G[u].push_back(Edge(v, w));
        G[v].push_back(Edge(u, w));  // 无向图
    }

    dijkstra();

    return 0;
}

在上面的代码中,我们在计算出最短路径后,使用了一个 vector 来保存从源节点到终点节点的路径。这个路径是从终点节点开始一直找前驱节点,直到找到源节点为止,然后再将路径反转过来,从源节点开始打印出来。

总结

在 Dijkstra 算法中打印路径并不是一个难点,只需要使用一个 vector 来保存路径,然后从终点节点开始一直找前驱节点,直到找到源节点为止,最后再将路径反转过来即可。同时,在实现过程中需要注意细节,例如源节点到自身的距离要设为0,更新距离和前驱节点时先判断是否更新等。