【算法】算法学习五:加权图 | 狄克斯特拉算法

一、加权图

加权图是指在图的边上赋予了权重(或距离)的图。每条边都带有一个数值,表示该边的权重。这种权重可以表示不同的度量,如距离、时间、成本等。

在加权图中,每个边都有一个相关的权重值,用于衡量通过该边的代价或消耗。这些权重可以是整数、浮点数或其他可比较的值。

加权图可以是有向图或无向图,具体取决于边的方向性。对于有向图,每条边都有一个起点和终点;而对于无向图,边没有明确的方向,可以在两个顶点之间双向移动。

加权图通常用于模拟现实世界中的各种场景,如网络路由、交通规划、物流问题等。通过使用加权图,可以考虑到不同路径上的代价或消耗,并找到最优的路径或解决方案。

在算法中,如狄克斯特拉算法(Dijkstra’s algorithm)和弗洛伊德算法(Floyd-Warshall algorithm),加权图的边权重被用于计算最短路径或最优解。这些算法可以解决最短路径问题、最小生成树问题、网络流问题等。

总结起来,加权图是指在图的边上赋予了权重的图。这些权重用于表示边的代价或消耗,可以应用于各种现实世界的模拟和问题求解。

二、负权边

负权边是指在加权图中,边的权重值为负数的边。在一般的加权图中,边的权重通常是非负数,表示通过该边的代价或消耗。但是,在某些情况下,负权边可能出现,并且在特定的算法和问题中具有重要的意义。

负权边的存在可能导致一些算法和问题的处理变得更加复杂或产生不同的结果。一些算法可能无法处理带有负权边的图,或者在处理负权边时需要特殊的处理方式。

以下是一些关于负权边的重要概念和算法:

  1. 负权环(Negative Cycle):负权环是指图中形成闭环的路径,其边的权重之和为负数。存在负权环时,最短路径和最短距离的概念就变得模糊或没有意义。例如,在狄克斯特拉算法中,如果图中存在负权环,则无法找到最短路径。
  2. 负权边的处理:对于某些算法,如贝尔曼-福特算法(Bellman-Ford algorithm),可以处理带有负权边的图。这些算法使用不同的策略来处理负权边,并确保得到正确的结果。贝尔曼-福特算法可以处理带有负权边和负权环的图,并找到最短路径。
  3. 最短路径问题中的负权边:在某些情况下,负权边可以用于解决特定的最短路径问题。例如,如果负权边表示节省成本或节省时间,那么在最短路径问题中可能需要选择包含负权边的路径,以获得更好的效果。

需要注意的是,负权边的存在可能改变算法的运行时间和结果。在使用算法处理带有负权边的图时,务必了解算法的限制和适用条件,并确保根据具体情况进行正确的处理和解释结果。

总结起来,负权边是指在加权图中,边的权重值为负数的边。它们在某些算法和问题中具有重要的意义,但也可能导致算法处理变得更加复杂或产生不同的结果。理解和处理负权边需要特殊的算法和策略,以确保得到正确的结果。

三、狄克斯特拉算法

3.1 理论知识

狄克斯特拉算法(Dijkstra’s algorithm)是一种用于解决单源最短路径问题的图算法。它可以找到从一个源节点到图中所有其他节点的最短路径。

以下是狄克斯特拉算法的详细步骤:

  1. 初始化:创建一个空集合visited用于记录已访问过的节点,并将源节点标记为已访问。创建一个距离字典dist,用于记录源节点到其他节点的当前最短距离。初始化dist中源节点为0,其他节点为正无穷大。
  2. 迭代过程:重复以下步骤,直到所有节点都被访问:

a. 从未访问的节点中选择距离最短的节点,将其标记为已访问,并加入visited集合。

b. 更新与该节点相邻的节点的最短距离。对于每个相邻节点,计算从源节点出发经过当前节点到达该相邻节点的距离。如果这个距离小于dist中记录的最短距离,则更新dist中该节点的最短距离为新的最短距离。

  1. 完成:当所有节点都被访问后,dist中记录的就是从源节点到达每个节点的最短距离。

狄克斯特拉算法基于贪心策略,每次选择距离最短的节点进行扩展,并更新与其相邻节点的最短距离。它适用于没有负权边的图,可以解决带权重的有向图或无向图中的最短路径问题。

狄克斯特拉算法的时间复杂度取决于图的规模和实现方式。使用优先队列(如最小堆)实现时,时间复杂度为 O((V + E)logV),其中 V 是节点数,E 是边数。当使用数组或列表实现时,时间复杂度为 O(V^2)。

需要注意的是,狄克斯特拉算法只能求解单源最短路径问题,即从一个源节点到其他所有节点的最短路径。如果需要求解任意两个节点之间的最短路径,可以使用其他算法,如弗洛伊德算法(Floyd-Warshall algorithm)。

总结起来,狄克斯特拉算法是一种用于解决单源最短路径问题的图算法。通过贪心策略和迭代更新节点的最短距离,它可以找到从源节点到图中所有其他节点的最短路径。

3.2 案例说明

以下是一个使用狄克斯特拉算法解决最短路径问题的案例:

假设有以下有向加权图:

      5       3
  (1) ----(2) ----(3)
   ▲       ▲       ▲
   │       │       │
4  │       │26
   │       │       │
   ▼       ▼       ▼
  (4) ----(5) ----(6)
      1       4

我们要找到从节点1到节点6的最短路径。

第一步,初始化:

  • visited集合:空集合
  • dist字典:节点1的最短距离为0,其他节点的最短距离为正无穷大

第二步,迭代过程:

  • 选择距离最短的节点1,将其标记为已访问,加入visited集合
  • 更新与节点1相邻的节点的最短距离:

节点2:当前距离为0 + 边(1,2)的权重5 = 5,小于正无穷大,更新节点2的最短距离为5

节点4:当前距离为0 + 边(1,4)的权重4 = 4,小于正无穷大,更新节点4的最短距离为4

第三步,继续迭代:

  • 选择距离最短的节点4,将其标记为已访问,加入visited集合
  • 更新与节点4相邻的节点的最短距离:

节点5:当前距离为4 + 边(4,5)的权重1 = 5,小于正无穷大,更新节点5的最短距离为5

第四步,继续迭代:

  • 选择距离最短的节点5,将其标记为已访问,加入visited集合
  • 更新与节点5相邻的节点的最短距离:

节点6:当前距离为5 + 边(5,6)的权重4 = 9,小于正无穷大,更新节点6的最短距离为9

第五步,所有节点都已访问,迭代结束。

最终,得到的最短距离为:

节点 1 到节点 1 的最短距离为:0
节点 1 到节点 2 的最短距离为:5
节点 1 到节点 3 的最短距离为:8
节点 1 到节点 4 的最短距离为:4
节点 1 到节点 5 的最短距离为:5
节点 1 到节点 6 的最短距离为:9

因此,从节点1到节点6的最短路径为1 -> 4 -> 5 -> 6,总距离为9。

3.3 Python代码实现

import sys

def dijkstra(graph, source):
    # 初始化距离字典
    dist = {node: sys.maxsize for node in graph}
    dist[source] = 0

    # 初始化访问过的节点集合
    visited = set()

    while len(visited) < len(graph):
        # 选择距离最短的节点
        min_dist = sys.maxsize
        min_node = None
        for node in graph:
            if node not in visited and dist[node] < min_dist:
                min_dist = dist[node]
                min_node = node

        # 将选择的节点标记为已访问
        visited.add(min_node)

        # 更新与选择节点相邻节点的最短距离
        for neighbor, weight in graph[min_node].items():
            new_dist = dist[min_node] + weight
            if new_dist < dist[neighbor]:
                dist[neighbor] = new_dist

    return dist

# 定义图的邻接表表示
graph = {
    1: {2: 5, 4: 4},
    2: {3: 3},
    3: {},
    4: {2: 2, 5: 1},
    5: {3: 6, 6: 4},
    6: {}
}

source_node = 1
distances = dijkstra(graph, source_node)

# 打印最短路径
for node, distance in distances.items():
    if distance == sys.maxsize:
        distance = "无穷大"
    print(f"节点 {source_node} 到节点 {node} 的最短距离为:{distance}")

运行以上代码,将输出每个节点与源节点的最短距离。对于给定的示例图,输出如下:

节点 1 到节点 1 的最短距离为:0
节点 1 到节点 2 的最短距离为:5
节点 1 到节点 3 的最短距离为:8
节点 1 到节点 4 的最短距离为:4
节点 1 到节点 5 的最短距离为:5
节点 1 到节点 6 的最短距离为:9

逐行解读如下:

  1. import sys: 导入sys模块,用于访问系统相关的功能。
  2. def dijkstra(graph, source): 定义了一个名为dijkstra的函数,用于执行狄克斯特拉算法。
  3. dist = {node: sys.maxsize for node in graph}: 初始化距离字典dist,将所有节点的初始距离设置为sys.maxsize(表示无穷大),graph是传入的图的邻接表表示。
  4. dist[source] = 0: 将源节点的距离设置为0,表示源节点到自身的距离为0。
  5. visited = set(): 初始化一个集合visited,用于存储已访问的节点。
  6. while len(visited) < len(graph):: 当已访问的节点数量小于图中的节点数量时,执行循环。
  7. min_dist = sys.maxsize: 将最短距离初始化为无穷大。
  8. min_node = None: 初始化最短距离对应的节点为None。
  9. for node in graph:: 遍历图中的所有节点。
  10. if node not in visited and dist[node] < min_dist:: 检查节点是否未被访问且距离更短。
  11. min_dist = dist[node]: 更新最短距离为当前节点的距离。
  12. min_node = node: 更新最短距离对应的节点为当前节点。
  13. visited.add(min_node): 将选择的节点标记为已访问。
  14. for neighbor, weight in graph[min_node].items():: 遍历选择节点的相邻节点和对应的权重。
  15. new_dist = dist[min_node] + weight: 计算选择节点到相邻节点的新距离。
  16. if new_dist < dist[neighbor]:: 如果新距离比原距离更短。
  17. dist[neighbor] = new_dist: 更新相邻节点的最短距离为新距离。
  18. return dist: 返回最短距离字典。
  19. graph是一个示例图的邻接表表示,包含了节点1到6的连接关系和对应的边权重。
  20. source_node = 1: 设置源节点为1。
  21. distances = dijkstra(graph, source_node): 调用dijkstra函数,计算最短路径。
  22. 46-51. 打印每个节点与源节点的最短距离。如果最短距离为sys.maxsize,则将其显示为"无穷大"。

代码实现了狄克斯特拉算法,并计算了源节点到其他节点的最短距离。

sys 是Python标准库中的一个模块,提供了与Python解释器及其环境交互的功能。它包含了许多与系统相关的操作和函数,可以访问和操作解释器的运行时环境。

以下是 sys 模块的一些常用功能和用途:

  1. 命令行参数:sys.argv 变量包含了程序执行时从命令行传递的参数列表。可以使用它来获取和解析命令行参数,以便在程序中进行相应的处理。
  2. 标准输入/输出:sys.stdin、sys.stdout 和 sys.stderr 变量提供了对标准输入、标准输出和标准错误流的访问。可以使用它们读取输入、输出结果和错误信息。
  3. 异常处理:sys.exc_info() 函数返回当前的异常信息。可以在异常处理代码中使用它来获取异常类型、异常值和追溯信息。
  4. 系统退出:sys.exit() 函数用于退出程序的执行,并返回指定的退出状态码。可以使用它来正常终止程序或指示错误发生。
  5. 系统配置和信息:sys.version 变量存储了当前Python解释器的版本信息。sys.platform 变量提供了当前操作系统的标识符。sys.getsizeof() 函数可以返回对象的内存大小。
  6. 模块导入和搜索路径:sys.path 变量包含了解释器在导入模块时搜索的路径列表。可以使用它来查找和调整模块搜索路径。
  7. 强制刷新输出:sys.stdout.flush() 函数用于强制刷新标准输出缓冲区,确保立即将输出显示在屏幕上。

这只是 sys 模块提供的一部分功能,还有其他一些功能和方法可供使用。通过使用 sys 模块,可以更好地与解释器环境进行交互,并进行一些与系统和运行时环境相关的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

旅途中的宽~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值