【图论Graph Theory】最短路问题与Floyd算法

一、什么是最短路

顾名思义,就是指从结点 s s s到结点 t t t的最短路径,通常记为 δ ( s , t ) \delta(s, t) δ(s,t)

二、解决最短路的方法

如下图表格:

单源最短路径(起点固定)全源最短路径(起点随意)
无负权边Dijkstra算法( O ( V log ⁡ 2 E ) O( V\log_2E) O(Vlog2E))Floyd算法( O ( V 3 ) O(V^3) O(V3))/Johnson算法
有负权边SPFA算法( O ( V E ) ) O(VE)) O(VE))同上

由于Johnson算法太过复杂,我们最后讲解。

三、Floyd算法详解:

Floyd算法是一种暴力算法,算法时间复杂度 O ( ∣ V ∣ 3 ) O(|V|^3) O(V3),下面是过程详解:

Floyd算法运用了动态规划思想,求两点间的距离,可以分两种情况,一种是经过某个点 k k k的路径,另一种是不经过点 k k k的路径。
动态规划的过程可描述为:
1.令 k = 1 k = 1 k=1,求出所有节点间的最短路径。
2.令 k = 2 k = 2 k=2,求出所有节点中的路径,与步骤一中结果所比较,进行更新。
⋯ \cdots

注意,Floyd算法最好使用邻接矩阵,除非两点间有重边或其余问题,适得其反不能使用邻接矩阵。

Floyd代码:

// 此处省略邻接矩阵储存图的步骤。
void floyd() {
	for (int i = 1; i <= n; i++)
		for (int s = 1; s <= n; s++)
			for (int t = 1; t <= n; t++)
				if (graph[i][j] > graph[i][k] + graph[k][j])
					graph[i][j] = graph[i][k] + graph[k][j];
}

学到这里,我们来挑战一下一道例题:

洛谷—采购特价商品

由于 n n n的范围较小,所以我们可以采用Floyd算法,这道题的坑点就在于他没直接给出两点间距离,所以我们介绍一个函数:

double hypot(double x, double y);

这个函数是计算 x 2 + y 2 \sqrt{x^2 + y^2} x2+y2 的,我们只需传参是传入连点坐标差,即可得出两点间距离。此函数存储在cmath库中,我们需要先导入头文件。所以标准代码如下:

#include <iostream>
#include <cmath>
using namespace std;
struct point {
    int x, y;
};
int main() {
    int n;
    cin >> n;
    point ps[n + 1];
    double g[n + 1][n + 1]; // 此处卡常,数组尽量开小一点。
    for (int i = 1; i <= n; i++) 
        for (int j = 1; j <= n; j++)
            g[i][j] = 100000;
    for (int i = 1; i <= n; i++) cin >> ps[i].x >> ps[i].y;
    int m;
    cin >> m;
    while (m--) {
        int u, v;
        cin >> u >> v;
        g[u][v] = g[v][u] = hypot(ps[u].x - ps[v].x, ps[u].y - ps[v].y); // 无向图存两条边
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            for (int k = 1; k <= n; k++)
                g[j][k] = min(g[j][k], g[j][i] + g[i][k]); // 简写代码
    int s, t;
    cin >> s >> t;
    printf("%.2lf", g[s][t]);
}

文末提示:对于Floyd,算法时间复杂度高,只适用于结点数 ∣ V ∣ ≤ 200 |V| \le 200 V200的图,其他图请使用SPFA或Dijkstra。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SZSKszmn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值