最短路三种算法详解

最短路

最短路问题即,给你一张图,让你求出图中两点的最短距离。

这篇文章会讲解 DijkstraSpfaFloyd 三种算法,让您透彻理解最短路!

Dijkstra#

朴素版#

题目:

image

Dijkstra 通常是用来解决图中一个定点到其余点的最短距离,基本思路是:从中心向外扩展,直到扩展到终点为止。

我们用 dist[u] 来表示从源点 su 的最短距离。

还需要维护一个状态数组 st,用于在更新最短距离时,判断当前的点的最短距离是否需要更新(是否已经确定)。

在每一次扩展的过程中,我们要先找到当前未确定的点的集合中找到一个距离最小的点,也就是:

int t = -1; // 距离最短的点的编号
for (int j = 1; j <= n; ++j) 
    if (!st[j] && (t == -1 || dist[j] < dist[t])) // 判断是否符合条件
        t = j;

那么我们就已经确定这个点了,把它的状态更新一下:

st[t] = true;

然后用这个点更新所有未确定点的最短距离

for (int j = 1; j <= n; ++j) 
    if (!st[i]) // 这句话其实可以不用加,因为我们dijkstra算法的性质已经确定后面确定的点不会再比现在的小了
        dist[j] = min(dist[j], dist[t] + g[t][j]);

完整代码:

#include <iostream>
#include <cstring>
#define N 510
using namespace std;
int n, m;
int g[N][N];
int dist[N];
bool st[N];
int dijkstra() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0; // 源点到源点的距离是0
    for (int i = 1; i <= n; ++i) {
        int t = -1;
        for (int j = 1; j <= n; ++j) 
            if (!st[j] && (t == -1 || dist[j] < dist[t])) 
                t = j;
        st[t] = true;
        for (int j = 1; j <= n; ++j) dist[j] = min(dist[j], dist[t] + g[t][j]);
    }
    if (dist[n] == 0x3f3f3f3f) return -1; // 不存在最短路径
    return dist[n];
}
int main() {
    memset(g, 0x3f, sizeof g);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = min(g[a][b], c); // 防止重边的情况
    }
    cout << dijkstra() << '\n';
    return 0;
}

此代码时间复杂度为 O(n2)

优化#

我们发现,朴素 Dijkstra 主要就耗时在找 t 上了;在一组数中找到一个最小值,我们自然可以想到用优先队列。

于是我们的代码就可以优化成这样了:

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
#define N 200000
typedef pair<int, int> PII; // 存储距离和节点编号
int n, m;
int h[N], e[N], w[N], ne[N], idx; // 因为是点数较多,所以用邻接表存图
int dist[N];
bool st[N];
void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; }
int dijkstra() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> q;
    q.push({0, 1});
    while (q.size()) {
        auto t = q.top();
        q.pop();
        int ver = t.second;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = h[ver]; i != -1; i = ne[i]) {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i]) {
                dist[j] = dist[ver] + w[i];
                q.push({dist[j], j});
            }
        }
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
int main() {
    memset(h, -1, sizeof h);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
    }
    cout << dijkstra() << '\n';
    return 0;
}

剩下的咕咕,明天再写。都咕两个月了还没补

作者:chinjinyu

出处:https://www.cnblogs.com/popfront/p/17659405.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   popcoount  阅读(37)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示