首页 > 其他分享 >dijkstra最短路代码模板更新

dijkstra最短路代码模板更新

时间:2022-12-17 11:55:30浏览次数:42  
标签:node dist min 短路 back dijkstra end neibor 模板



 

from collections import defaultdict
from heapq import heappush, heappop


def dijkstra(edges, start_node, end_node):
    graph = defaultdict(dict)
    for src, dst, distance in edges:
        graph[src][dst] = distance

    q = [(0, start_node, None)]
    found_min_dist_nodes = set()
    distances = {start_node: 0}
    back_paths = {}

    while q:
        cost, min_dist_node, src_node = heappop(q)

        #  下面这行代码非常关键,是为了去除优先级队列q里冗余的push,见后注释说明重复节点push问题
        #if min_dist_node in found_min_dist_nodes:
        #    continue

        found_min_dist_nodes.add(min_dist_node)
        back_paths[min_dist_node] = src_node

        if min_dist_node == end_node:
            return cost, back_paths

        for neibor_node, distance in graph[min_dist_node].items():
            if neibor_node in found_min_dist_nodes:
                continue

            prev_dist = distances.get(neibor_node, float('inf'))
            new_dist = cost + distance
            if new_dist < prev_dist:
                distances[neibor_node] = new_dist
                # 下面这个代码,正常情况下,应该是更新优先级队列里neibor_node的priority value
                # 但因为priority queue无原生更新api支持,所以下面代码是在没有remove neibor_node的情况直接push,会导致重复节点push
                heappush(q, (new_dist, neibor_node, min_dist_node))

    return float("inf"), back_paths


def find_path(back_paths, start_node, end_node):
    ans = [end_node]
    while end_node != start_node:
        end_node = back_paths[end_node]
        ans.append(end_node)

    return ans[::-1]


if __name__ == "__main__":
    edges = [
        ("A", "B", 5),
        ("A", "C", 10),
        ("C", "D", 10),
        ("B", "C", 2)]

    dist, backpaths = dijkstra(edges, "A", "D")
    print("dist: ", dist)
    print(find_path(backpaths, "A", "D"))

  

上面案例中的图示例:

A--------(5)--------->B

|                         /

(10)                / (2)

|                /

      C

      |(10)

     D

 

肉眼看,A->D的最短路距离是17,路径是ABCD。

 

如果没有下面的代码:

        if min_dist_node in found_min_dist_nodes:
             continue

输出A到D的最短距离和路径为:

dist: 17
['A', 'C', 'D']

路径这个答案是错的!!!路径计算错了!但是距离计算是ok的!

为啥呢???因此C节点会重复push,debug下就可以看出来了:

 

 

 

因此,我们加上上述if判定进行去重,因为之前已经pop过了,再pop重复节点已经没有意义:

from collections import defaultdict
from heapq import heappush, heappop


def dijkstra(edges, start_node, end_node):
    graph = defaultdict(dict)
    for src, dst, distance in edges:
        graph[src][dst] = distance

    q = [(0, start_node, None)]
    found_min_dist_nodes = set()
    distances = {start_node: 0}
    back_paths = {}

    while q:
        cost, min_dist_node, src_node = heappop(q)

        #  下面这行代码非常关键,是为了去除优先级队列q里冗余的push,见后注释说明重复节点push问题
        if min_dist_node in found_min_dist_nodes:
            continue

        found_min_dist_nodes.add(min_dist_node)
        back_paths[min_dist_node] = src_node

        if min_dist_node == end_node:
            return cost, back_paths

        for neibor_node, distance in graph[min_dist_node].items():
            if neibor_node in found_min_dist_nodes:
                continue

            prev_dist = distances.get(neibor_node, float('inf'))
            new_dist = cost + distance
            if new_dist < prev_dist:
                distances[neibor_node] = new_dist
                # 下面这个代码,正常情况下,应该是更新优先级队列里neibor_node的priority value
                # 但因为priority queue无原生更新api支持,所以下面代码是在没有remove neibor_node的情况直接push,会导致重复节点push
                heappush(q, (new_dist, neibor_node, min_dist_node))

    return float("inf"), back_paths


def find_path(back_paths, start_node, end_node):
    ans = [end_node]
    while end_node != start_node:
        end_node = back_paths[end_node]
        ans.append(end_node)

    return ans[::-1]


if __name__ == "__main__":
    edges = [
        ("A", "B", 5),
        ("A", "C", 10),
        ("C", "D", 10),
        ("B", "C", 2)]

    dist, backpaths = dijkstra(edges, "A", "D")
    print("dist: ", dist)
    print(find_path(backpaths, "A", "D"))

  

  输出:

dist: 17
['A', 'B', 'C', 'D']

这下就对了!!!

 

因此对于dijkstra最短路代码,还是要加上if判定!

 

标签:node,dist,min,短路,back,dijkstra,end,neibor,模板
From: https://www.cnblogs.com/bonelee/p/16988799.html

相关文章

  • 40 个超棒的免费 Bootstrap HTML5 网站模板
     ​​​​Bootstrap是快速开发Web应用程序的前端工具包。它是一个CSS和HTML的集合,它使用了最新的浏览器技术,给你的Web开发提供了时尚的版式,表单,buttons,表格,网......
  • 【微服务】微服务框架模板项目
    微信公众号:【后端研发Marion】加微信进JAVA技术交流群微信公众号微信群(备注:加群)【Marion-Micro】微服务模版框架一、目标1.作为传统单体服务改造成微服务架构的模板项目2.......
  • ECMall2.x模板制作入门系列之(模板标签/语法)
    在ECMall模板中,用”{“开头,以”}”结尾就构成一个标签单元,”{“紧接着的单词就是标签名。在标签单元中单词前含”$”(美元符)的为变量名。一、资源引用res标签功能:返回当......
  • ADS 流水线模板
    经典模式AzureDevopsServer2019,TeamFoundationServer2018另存为模版即可可以在模版上管理权限,比如不能修改模版但是继承模版后依然可以随意调整Yaml文件模式......
  • 零基础学 Vue + Element UI 第01步 —— 搭建开发环境、创建项目、修改默认模板、启动
    通过对《零基础学前端系列教程|和前端谈恋爱的第001–006天》的学习,我们已经基本掌握了HTML的核心标签,CSS的常见样式,对Javascript也略有接触。零基础学前端系列教程|......
  • 美化模板测试
    标题一dsadasdfsadasasd打防守打法第三方s发生大幅度标题二正式服是这是大V早上的招待费GV个大概富商大贾个反的个个公司搞法高富帅搞法苟富贵发搞法苟富贵发个施工......
  • 子矩阵的和【模板题】
    子矩阵的和输入一个n行m列的整数矩阵,再输入q个询问,每个询问包含四个整数\(x1,y1,x2,y2\),表示一个子矩阵的左上角坐标和右下角坐标。对于每个询问输出子矩阵中所有......
  • 前缀和【模板题】
    前缀和输入一个长度为n的整数序列。接下来再输入m个询问,每个询问输入一对l,r。对于每个询问,输出原序列中从第l个数到第r个数的和。输入格式第一行包含两个整......
  • 刷题笔记 | 算法模板题-回文判定
    题目描述给定一个长度为n的字符串S。请你判断字符串S是否回文。输入描述输入仅1行包含一个字符串S。\(1\leq|S|\leq10^6\),保证S只包含大小写、字母。输......
  • Django之模板层
    Django之模板层目录Django之模板层模板语法传值模板层之标签自定义过滤器、标签及inclusion_tag模板的继承与导入模型层之前期准备ORM常用关键字模板语法传值方法一、#......