一说到最短路径,啊,多么痛的领悟,我始终过不去这道坎!总是忘了,最近春招了,记下来吧!!
- 方法一 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))