图之最短路径

本文深入探讨了三种经典的最短路径算法:深度优先搜索(DFS)、弗洛伊德(Floyd)算法及迪杰斯特拉(Dijkstra)算法。通过实例讲解了每种算法的工作原理与实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一说到最短路径,啊,多么痛的领悟,我始终过不去这道坎!总是忘了,最近春招了,记下来吧!!

  • 方法一   DFS(深度优先)(求单源距离最短)(暴力解决)(回朔!!!)

自己看代码吧

简单的话总结一下就是:若节点数为n  ,建立好邻接矩阵(n+1 * n+1 )(初始化[i][i] = 0;没有边的节点=inf;)、访问矩阵(n+1) (初始化[i] = 0 )。在这里说一下为啥大小为(n+1),这个看你输入的节点编号定义是从哪里开始的(随题意走)。如果从1开始,建议n+1

然后从节点1开始回朔递归,直到到目的节点。还是看代码吧!

class Solution:
    def __init__(self,n,m):
        self.n = n  # 节点数
        self.m = m   # 节点之间的边数
        self.minpath = 1e12
        
        # 初始化邻接矩阵  [i][i]=0 [i][j] = inf 
        self.edge = [[1e12]*(n+1) for i in range(n+1)]  # 邻接矩阵

        #--------------------构建邻接矩阵
        for i in range(n+1):
            self.edge[i][i] = 0

        # 命令行输入 2 3 9  代表 2到3节点 权重为9
        for i in range(m):
            line = input()
            l_array = [int(k) for k in line.split(' ')]
            self.edge[l_array[0]][l_array[1]] = l_array[2]

        # 判断是否访问过 用于剪枝
        self.mark = [0] * (n+1)
    
    # DFS主函数入口
    def getMinPath(self):
        
        self.mark[1] = 1
        # 从节点1开始遍历 此时距离为0
        self.dfs(1, 0)

        return self.minpath
    
    def dfs(self, cur, dst):
        # cur代表目前走到了节点cur 距离总和是dst  
        
        # 如果到达目的地 并且找到了更短路径的话 更新最短路径 返回
        if cur == self.n:
            if self.minpath >dst:
                self.minpath = dst
                return
        
        if self.minpath < dst:
            # 剪枝  如果现在的距离已经比之前一种方案得到的距离要远 那就不要往下走了
            return
        
        # 这他妈就是回朔法嘛!!!  遍历所有的可选节点
        for i in range(1,self.n+1):
            # 选择节点cur还没有遍历过的近邻
            if self.edge[cur][i] != 1e12 and self.edge[cur][i] !=0 and self.mark[i] == 0:
                self.mark[i] = 1
                self.dfs(i, dst + self.edge[cur][i])
                self.mark[i] = 0
        
        
so = Solution(5, 8)
print(so.getMinPath())

 

答案输出为9

  • Floyd算法(求多源距离最短)

算法思想:每次新增加一个节点进去,代表其他节点之间可以路过该节点,从而更新节点之间的最短距离。更新规则是:如果目前节点i和节点j之间的距离小于路过节点k的距离的话,就更新该节点。edge[ i ][ j ] < edge[ i ][ k ] + edge[ 1 ][ k ], k为中转节点。

上代码吧


class Solution:
    def __init__(self,n,m):
        self.n = n
        self.m = m
        self.minpath = 1e12
        
        # 通过命令行输入 初始化邻接矩阵  [i][i]=0 
        self.edge = [[1e12]*(n+1) for i in range(n+1)]
        for i in range(n+1):
            self.edge[i][i] = 0
        # 命令行输入 2 3 9  代表 2到3节点 权重为9
        lines = ['1 2 2','1 5 10','2 3 3','2 5 7','3 1 4','3 4 4','4 5 5','5 3 3']
        for i in range(m):
            line = lines[i]
            l_array = [int(k) for k in line.split(' ')]
            self.edge[l_array[0]][l_array[1]] = l_array[2]
        # 判断是否访问过 用于剪枝
        self.mark = [0] * (n+1)
       
    
    def floyd(self):
        for k in range(1, self.n+1):   # 添加一个可中转的新节点进来
           for i in range(1, self.n+1):  # 遍历edge起始节点
               for j in range(1, self.n+1):  遍边edge终点
                   if self.edge[i][k] < 1e12 and self.edge[k][j] < 1e12:
                        # 如果节点i到节点j能通过新添加的节点k中转  也就是说边i->k存在 以及 边k->j存在的话
                        # 更新该节点的值 min(当前值,中转之后的值)
                       self.edge[i][j] = min(self.edge[i][j], self.edge[i][k]+self.edge[k][j])
        return self.edge# 返回所有节点之间的最短路径
so = Solution(5, 8)
#print(so.getMinPath())
print(so.floyd())
  • Dijieskra

算法思想:

class Solution:
    def __init__(self,n,m):
        self.n = n
        self.m = m

        # 通过命令行输入 初始化邻接矩阵  [i][i]=0 
        self.edge = [[1e12]*(n) for i in range(n)]
        for i in range(n):
            self.edge[i][i] = 0
        # 命令行输入 2 3 9  代表 2到3节点 权重为9
        lines = ['0 1 2','0 4 10','1 2 3','1 4 7','2 0 4','2 3 4','3 4 5','4 2 3']
        for i in range(m):
            line = lines[i]
            l_array = [int(k) for k in line.split(' ')]
            self.edge[l_array[0]][l_array[1]] = l_array[2]
    
    def Dijiskla(self, ori):
        # 定义源点ori到 其他顶点的距离
        self.dst = self.edge[ori]
        # 定义已经确定最短距离的节点集合
        self.already = [ori]
        
        while len(self.already) != self.n:
           # 1. 找到最除还没有确定最短路径的节点集中,距离最短的那个节点
           arg_min = self.arg_min()
           
           # 2. 把节点添加到already中
           self.already.append(arg_min)
           
           
           # 3. 更新dst节点
           for i,val in enumerate(self.dst):
               
               if i not in self.already:
                    
                   self.dst[i] = min(self.dst[arg_min] + self.edge[arg_min][i],self.dst[i])
                   
        return self.dst
    
    def arg_min(self):
        # 返回距离最近的那个节点
        min_num = 1e12
        min_ind = -1
        for i,val in enumerate(self.dst):
            if i not in self.already and val < min_num:
            # 还没有确定最短路径的节点 
                min_num = val
                min_ind = i
        return min_ind
                   

so = Solution(5, 8)
print(so.Dijiskla(0))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值