内容还是比较详细的,这里不废话了,代码里都有
注意的是,绿色线尽头的点是:起点到达该点的最短距离
算法会寻找每个点临近点中最近的点,排除掉已经访问过的点
(matplotlib坏了还没修好,暂时用的cv2绘制)
python
import math
import cv2
import numpy as np
class Dj:
def __init__(self, points, start, end):
self.points, self.start, self.end = points, start, end
self.w, self.h = 1000, 600
self.image = np.zeros((self.h, self.w, 3), dtype=np.uint8)
self.route = []
self.generate_map()
self.video = cv2.VideoWriter("output.mp4", cv2.VideoWriter_fourcc(*'XVID'), 1, (self.w, self.h)) # 录制
def generate_map(self):
for p in self.points:
cv2.circle(self.image, p, 10, (0, 0, 255), - 1)
for ps in self.points[p]:
cv2.line(self.image, p, ps, (255, 255, 255), 4)
def line_shortest(self, p1, p2):
cv2.line(self.image, p1, p2, (0, 255, 0), 4)
return p2
def line_route(self):
for i in range(1, len(self.route) - 1):
cv2.line(self.image, self.route[i - 1], self.route[i], (0, 255, 255), 4)
def distance(self, point1, point2):
return math.sqrt((point1[0] - point2[0]) ** 2 + (point1[1] - point2[1]) ** 2)
# Dijkstra算法实现
def dijkstra(self):
dist = {point: float('inf') for point in self.points} # 点:起点到当前点的最短距离
dist[self.start] = 0 # 起点到自身距离设为0
prev = {point: None for point in self.points} # 记录每个点的前驱节点,用于回溯最短路径
visited = set() # 以及访问过的点
while len(visited) < len(self.points): # 未访问所有点
frame = self.image.copy()
current = None # 到达的当前点为None
min_dist = float("inf") # 对于全部点,起点到达该点的最短距离
# ########################################### 更新起点到当前点的所经过的最短路径(总距离) 和 当前点
for point in points: # 对于每个点
if point not in visited and dist[point] < min_dist: # 如果未访问,且起点到当前点的距离小于全局最短距离
min_dist = dist[point] # 更新全局最短距离
current = point # 更新到达的点
visited.add(current) # 在目前距离最优的情况下,该点已访问
##############################################
if current == self.end:
break # 如果到达的点是终点,结束
# ############################################# 更新起点到当前点相邻点中最近的点,和 到达距离
for neighbor in points[current]: # 对于当前点的所有相邻点
new_dist = dist[current] + self.distance(current, neighbor) # 更新起点到当前点的相邻点的总距离
color = (255, 0, 0)
if new_dist < dist[neighbor]: # 如果这个距离是起点到该点相邻点的最短距离
dist[neighbor] = new_dist # 更新起点到达该点相邻点的最短距离
prev[neighbor] = current
color = (0, 255, 0)
self.line_shortest(current, neighbor) # 在原图上绘制到达该点的最短路径
if neighbor in visited: # 避免画回头的线
continue
cv2.line(frame, neighbor, current, color, 4) # 绘制临近点的路径
cv2.waitKey(1000)
##############################################
cv2.imshow("dj", frame)
self.video.write(frame)
cv2.imshow('dj', self.image)
self.video.write(self.image)
cp = self.end
self.route = [cp]
while cp:
self.route.append(prev[cp])
cp = prev[cp]
cv2.waitKey(1000)
self.line_route()
cv2.imshow('dj', self.image)
self.video.write(self.image)
self.video.release()
key = cv2.waitKey()
if key == 27: # 如果按下ESC键(ASCII码值为27),退出循环
cv2.destroyAllWindows()
return dist
# points = {
# (0, 0): [(0, 200), (200, 300), (400, 100)],
# (0, 200): [(200, 300), (0, 0)],
# (200, 300): [(0, 200), (0, 0), (500, 500)],
# (400, 100): [(0, 0), (500, 500)],
# (500, 500): [(200, 300), (400, 100)],
# }
# 点与其相邻点
points = {
(0, 0): [(400, 0), (0, 200), (500, 300)],
(400, 0): [(0, 0), (700, 100)],
(0, 200): [(0, 0), (300, 350)],
(300, 350): [(0, 200), (400, 500)],
(400, 500): [(300, 350), (600, 600)],
(600, 600): [(400, 500), (500, 300), (1000, 600)],
(500, 300): [(0, 0), (700, 100), (1000, 250), (600, 600)],
(700, 100): [(400, 0), (500, 300), (1000, 250)],
(1000, 250): [(700, 100), (500, 300), (900, 400)],
(900, 400): [(1000, 250), (1000, 600)],
(1000, 600): [(1000, 250), (600, 600)]
}
d = Dj(points, (0, 0), (1000, 600))
d.dijkstra()