最短路问题--Floyd


提示:以下是本篇文章正文内容,下面案例可供参考

一、介绍

Floyd算法是一种用来计算图中所有点之间最短距离的算法。它的核心思想是:通过逐步尝试每个点作为中间点,看看能不能让其他两点之间的距离变得更短。

二、补充知识:邻接矩阵

邻接矩阵是一种用来表示图的结构的工具,它用一个二维数组来记录图中各个顶点之间的关系。简单来说,就是用一个表格来描述图中哪些点之间有边,以及边的权重。

  1. 邻接矩阵的定义

假设有一个图,包含 n 个顶点,编号为 1 到 n。邻接矩阵是一个 n×n 的二维数组 adj,其中:
adj[i][j] 表示顶点 i 和顶点 j 之间的关系。
如果顶点 i 和 j 之间有边,那么 adj[i][j] 的值是边的权重(如果是无权图,则标记为 1)。
如果顶点 i 和 j 之间没有边,那么 adj[i][j] 的值通常设为 0 或无穷大(取决于具体需求,一般inf)

2.说简单一点

行对应元素到列元素的距离,就是存在矩阵的值
对角线为0,因为自己到自己为0
在这里插入图片描述
在这里插入图片描述

三、原理

1.首先创建一个邻接矩阵,全部设为0
2.初始化邻接矩阵,即此时不使用中转节点,就是点到点的直接距离,倘若点到点走不通,那就设为inf即可,记住:邻接矩阵的对角线一点都是0
3.遍历所有节点作为中转节点,这个点所在的行列无需变动,原理如下:

倘若1为中间节点,则1->2和1->1->2没有区别,自己到自己距离为0,同理3->1,和3->1->1也是一样的

4.对于除上述所说的自己的行列除外,对角线也除外,剩下的元素开始迭代更新
5.如果经过了中转节点的路劲之和小于上一步的,就更新矩阵,知道结束

上述内容若觉得云里雾里:推荐这个视频——>B站up主sunny光合

四、实现

以下代码,包括回溯路径,使用字典转邻接矩阵

graph={
    'A':{'B':1,'C':4},
    'B':{'A':1,'C':2,'D':5},
    'C':{'A':4,'B':2,'D':1},
    'D':{'B':5,'C':1}
}

def floyd(graph):
    # 获取顶点列表
    vertices = list(graph.keys())
    n = len(vertices)
    
    # 初始化距离矩阵和路径矩阵
    dist = [[float('inf')] * n for _ in range(n)]
    next = [[None] * n for _ in range(n)]
    
    # 填充邻接矩阵和路径矩阵
    for i in range(n):
        for j in range(n):
            if i == j:
                dist[i][j] = 0
            elif vertices[j] in graph[vertices[i]]:
                dist[i][j] = graph[vertices[i]][vertices[j]]
                next[i][j] = j  # 记录路径,从i到j的下一跳是j

    # Floyd算法核心
    for k in range(n):  # 中间点
        for i in range(n):  # 起点
            for j in range(n):  # 终点
                if dist[i][k] + dist[k][j] < dist[i][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]
                    next[i][j] = next[i][k]  # 更新路径

    # 打印最短路径长度矩阵
    print("最短路径长度矩阵:")
    for row in dist:
        print(row)

    # 回溯路径
    def reconstruct_path(start, end):
        if dist[start][end] == float('inf'):
            return None  # 无路径
        path = [start]
        while start != end:
            start = next[start][end]
            path.append(start)
        return path

    # 打印路径
    print("\n路径信息:")
    for i in range(n):
        for j in range(n):
            if i != j:
                path = reconstruct_path(i, j)
                if path:
                    print(f"{vertices[i]} -> {vertices[j]}: {list(map(lambda x: vertices[x], path))}")
                else:
                    print(f"{vertices[i]} -> {vertices[j]}: 无路径")

# 调用算法
floyd(graph)

输出结果

最短路径长度矩阵:
[0, 1, 3, 4]
[1, 0, 2, 3]
[3, 2, 0, 1]
[4, 3, 1, 0]

路径信息:
A -> B: ['A', 'B']
A -> C: ['A', 'B', 'C']
A -> D: ['A', 'B', 'C', 'D']
B -> A: ['B', 'A']
B -> C: ['B', 'C']
B -> D: ['B', 'C', 'D']
C -> A: ['C', 'B', 'A']
C -> B: ['C', 'B']
C -> D: ['C', 'D']
D -> A: ['D', 'C', 'B', 'A']
D -> B: ['D', 'C', 'B']
D -> C: ['D', 'C']

声明:
本文为本人的学习笔记,旨在记录和分享个人在学习过程中的心得体会和原创代码。由于本人刚入门,对相关知识的理解可能还存在不足之处,文章中难免会有错误或不准确的地方。在此,我诚挚地欢迎各位读者在阅读过程中,如果发现任何问题或有其他建议,随时在评论区或通过其他方式与我交流。我将虚心听取大家的意见,及时修正和改进文章内容,以便更好地学习和成长。感谢大家的关注和支持!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值