最近在考研复习,刚好学到图这一章了,然后也是学到关于图最难的几个部分了,一个是最小生成树(Prim算法和Kruskal算法),还一个就是最短距离问题了(Dijkstra算法和Floyd算法),我感觉前三个算法都还蛮好理解,就是最后一个Floyd有点没整明白,前三个算法基本上都用到贪心的思想,Prim每次都选择当前未使用的消耗最小的顶点(选点);Kruskal每次都是当前未使用的权值最小的边(选边);Dijkstra的思想和Prim的思想大致一直。
这里我就直接贴出源码了,python实现的,有兴趣的可以运行试试(反正考研也不会考python代码)
Dijkstra算法求最短路径
# -*- coding: UTF-8 -*-
'''
*****************LLL*********************
* @Project :leetcode
* @File :lll_107Dijkstra算法求解最短路径.py
* @IDE :PyCharm
* @Author :LLL
* @Date :2022/6/1 9:22
*****************************************
'''
def dijkstra_min_distance(start, target, graph):
if start not in graph['V'] or target not in graph['V']: return '无效起点或终点!'
visited = {} # 记录顶点的访问情况
dist = {} # 记录最短距离
path = [start] # 记录最短路径上的每一个顶点
V, E = graph['V'], graph['E']
for node in V:
visited[node] = 0 # 0表示没有访问 1表示已访问
dist[node] = -1 # -1表示无限远
dist[start] = 0 # 到自己的距离为0
visited[start] = 1
# 初始化到各顶点的距离
for e in E:
if e[0] == start:
dist[e[1]] = E[e]
# while not all(visited.values()): # 直到访问完所有顶点 求到所有顶点的最短距离
while not visited[target]: # 仅求到终点的距离
# 在所有可达的但未访问的顶点中,寻找距离最近的一个
cur_E_li = [(e, E[e]) for e in E if visited[e[0]] and not visited[e[1]]] # 所有可达但未访问的顶点
cur_E_li.sort(key=lambda a: a[1]) # 按照距离进行排序
print(cur_E_li)
min_edge_w = cur_E_li[0] # 第一个就是距离最短的那一个
new_start_node = min_edge_w[0][1]
# 刷新最短距离
for node in dist:
new_edge = (new_start_node, node)
if new_edge in E:
if dist[node] == -1:
dist[node] = dist[new_start_node] + E[new_edge]
else:
dist[node] = min(dist[node], dist[new_start_node] + E[new_edge])
# 更新visited
visited[new_start_node] = 1
path.append(new_start_node) # 将当前节点更新到最短路径上
return path, dist[target]
if __name__ == '__main__':
V = {1, 2, 3, 4, 5} # 顶点集
E = { # 边集
(1, 2): 10, # (起点,终点):权值
(1, 5): 5,
(2, 3): 1,
(2, 5): 2,
(3, 4): 4,
(4, 1): 7,
(4, 3): 6,
(5, 2): 3,
(5, 3): 9,
(5, 4): 2,
}
graph = {
'V': V,
'E': E
}
print(dijkstra_min_distance(1, 4, graph))
Prim算法求最小生成树
# -*- coding: UTF-8 -*-
'''
*****************LLL*********************
* @Project :leetcode
* @File :lll_108Prim算法求最小生成树.py
* @IDE :PyCharm
* @Author :LLL
* @Date :2022/6/1 18:58
*****************************************
'''
# prim算法
'''
核心:初始时从图中任取一顶点加入树T,此时树中只含有一个顶点,之后
选择一个与当前T中顶点集合距离最近的顶点,并将该顶点加入树T中,直到
所有顶点都被加入树T。
'''
from math import inf
def prim_min_span_tree(graph):
visited = {node: 0 for node in graph} # 用于表示一个顶点是否被访问
root = 1 # 任意取一个顶点
visited[root] = 1
T_w = {}
while not all(visited.values()): # 只要不是所有的顶点被访问了,就一直进行下去
# 查找与树T距离最近,但未被访问的顶点
not_visited_nodes = {node for node in graph if not visited[node]} # 未被访问的顶点
visited_nodes = {node for node in graph if visited[node]} # 树T
min_distance = inf
min_node = None
min_edge = None
# 求到树T距离最近的节点
for t in visited_nodes:
for node in not_visited_nodes:
cur_edge = '-'.join(map(str, sorted((t, node))))
cur_w = W.get(cur_edge, -1) # 当前边的权重
if cur_w != -1 and cur_w < min_distance:
min_distance = cur_w
min_node = node
min_edge = cur_edge
print(f'当前距离树T最近的节点:{min_node},权重为:{min_distance}')
T_w[min_edge] = min_distance # 添加到树T的权重记录表中
visited[min_node] = 1 # 更新当前节点为已访问
print(T_w)
if __name__ == '__main__':
# 邻接表法表示图
graph = {
1: {2, 3, 4},
2: {1, 3, 5},
3: {1, 2, 4, 5, 6},
4: {1, 3, 6},
5: {2, 3, 6},
6: {3, 4, 5}
}
W = {
'1-2': 6,
'1-3': 1,
'1-4': 5,
'2-3': 5,
'2-5': 3,
'3-4': 5,
'3-5': 6,
'3-6': 4,
'4-6': 2,
'5-6': 6
} # 权重
print(prim_min_span_tree(graph))
同步更新于个人博客系统:python实现Dijkstra算法求最短路径