一、简单BFS算法
bfs即广度优先搜索,最基础的寻路算法
即向出发点向四周无目的扩散,直到到达终点或者无法扩散为止
# coding: utf-8
import random
import bisect
class Solution(object):
def __init__(self, n, m, bad):
self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
# 目的点
self.end_point = (m - 1, n - 2)
self.max_x = m
self.max_y = n
def show_map(self):
print("##########start###########")
for map in self.map:
print(map)
print("##########end###########")
def g_bfs(self):
visited = set([])
queue = []
start = (0, 0)
queue.append(start)
while queue:
point = queue.pop(0)
point_x, point_y = point
visited.add(point)
self.map[point_x][point_y] = 9
if point == self.end_point:
return
for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
x = point_x + add_x
y = point_y + add_y
if x < 0 or x >= self.max_x:
continue
if y < 0 or y >= self.max_y:
continue
if self.map[x][y] != 0:
continue
if (x, y) in queue:
continue
queue.append((x, y))
if __name__ == "__main__":
s = Solution(10, 10, 40)
s.show_map()
s.g_bfs()
s.show_map()
结果:
9为路径
1为墙
计算点与点之间最短距离有以下三种
分别为:曼哈顿估价法、几何估价法、对角线估价法
接下来的算法遍历点时候,根据点与点距离优先遍历,我们一般采用曼哈顿方法计算
二、Dijkstra
Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,其流程仍然与上述算法基本一致。
但是出发点向四周扩散时候,优先从距离出发点更近的点出发
代价函数f(n)的定义,Dijkstra算的f(n)定义为:
f(n)=g(n)
其中g(n)表示从起点到当前点的移动代价
# coding: utf-8
import random
import bisect
class Solution(object):
def __init__(self, n, m, bad):
self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
# 目的点
self.end_point = (m - 1, n - 2)
self.max_x = m
self.max_y = n
def show_map(self):
print("##########start###########")
for map in self.map:
print(map)
print("##########end###########")
def g_bfs(self):
visited = set([])
queue = []
start = (0, 0)
queue.append(start)
while queue:
point = queue.pop(0)
point_x, point_y = point
visited.add(point)
self.map[point_x][point_y] = 9
if point == self.end_point:
return
for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
x = point_x + add_x
y = point_y + add_y
if x < 0 or x >= self.max_x:
continue
if y < 0 or y >= self.max_y:
continue
if self.map[x][y] != 0:
continue
if (x, y) in queue:
continue
queue.append((x, y))
queue.sort(key=self.manhattan) # 排序优先距离出发点最短的点,可以不用排序,便历一遍找到对应的点即可
def manhattan(self, start_point):
return abs(self.end_point[0] - 0) + abs(self.end_point[1] - 0)
if __name__ == "__main__":
s = Solution(10, 10, 40)
s.show_map()
s.g_bfs()
s.show_map()
结果:
三、A Star
A Start和目的BFS基本一样,优先遍历点的策略不一样
A*算法在运算过程中,每次从优先队列中选取$f(n)$值最小(优先级最高)的节点作为下一个待遍历的节点。
A*算法的启发公式可表示为:
f∗(n)=g∗(n)+h∗(n)
其中:
f*(n) 是从初始状态经由状态n到目标状态的最小代价估计
h*(n) 是从状态n到目标状态的路径的最小估计代价
(注:对于路径搜索问题,状态就是图中的节点,代价就是距离,即就是到达目标点代价代价最小的点)
# coding: utf-8
import random
class Node(object):
def __init__(self, point, g, h):
self.point = point
self.g = g # 起点到移动点的代价
self.h = h # 移动点到终点的代价
def __hash__(self):
return self.point
def cost(self):
# 起点到移动点的代价 + 移动点到终点的代价
return self.g + self.h
class AStar(object):
def __init__(self, n, m, bad):
self.map = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
[0, 1, 1, 1, 1, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 1, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
self.openList = []
self.closeList = {}
self.startNode = (0, 0)
self.endNode = (m - 1, n - 2)
self.max_x = m
self.max_y = n
def show_map(self):
print("##########start###########")
for map in self.map:
print(map)
print("##########end###########")
def starAStar(self):
g = manhattan(self.startNode, self.startNode)
h = manhattan(self.startNode, self.endNode)
add_node = Node(self.startNode, g, h)
self.openList.append(add_node)
self.closeList[add_node.point] = add_node
while self.openList:
node = self.openList.pop(0)
point_x, point_y = node.point
self.map[point_x][point_y] = 9
for add_x, add_y in ((0, -1), (-1, 0), (1, 0), (0, 1)):
x = point_x + add_x
y = point_y + add_y
if x < 0 or x >= self.max_x:
continue
if y < 0 or y >= self.max_y:
continue
if self.map[x][y] != 0:
continue
if (x, y) in self.closeList:
continue
if (x, y) == self.endNode:
# 结束
return
g = manhattan(self.startNode, (x, y)) # 目标状态到初始位置最小代价
h = manhattan((x, y), self.endNode) # 目标状态的路径的最小估计代价
add_node = Node((x, y), g, h)
self.closeList[add_node.point] = add_node
self.openList.append(add_node)
self.openList.sort(cmp=cmp_point) # 优先遍历代价最小的点,可以不排序,直接遍历找到最小代的点
def manhattan(point, end_point):
# 曼哈顿计算距离
return abs(point[0] - end_point[0]) + abs(point[1] - end_point[1])
def cmp_point(a, b):
if a.cost() == b.cost():
return cmp(a.h, b.h)
return cmp(a.cost(), b.cost())
if __name__ == "__main__":
s = AStar(10, 10, 40)
s.show_map()
s.starAStar()
s.show_map()
结果:
推荐一个寻路动态显示网站:PathFinding.js