一、实验任务
场地中正方格代表障碍物,选取小车运动起点和终点。编程探究小车从起点运动到终点,总共有几种可行的路径(路径不含重叠部分),同时找出最短路径并可视化。
二、实验思路
把场地抽象化为6×9的平面矩阵,然后从起点出发,随机选择一个可行方向(不返回、无障碍)运动一步,直至到达终点,找到可行路径。通过蒙特卡罗思想多次进行试验,记录每条成功路径的路径长度,找出最短路径,最终使用matplotlib将场地和最短路径可视化。
三、python代码实现
import numpy as np
import matplotlib.pyplot as plt
import random# 设置中文字体
# 这里使用SimHei字体, 可以根据实际字体路径设置
plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号无法显示的问题# 场地矩阵
map = np.array([[1, 1, 1, 0, 1, 1, 1, 1, 1],[1, 0, 1, 0, 1, 0, 1, 0, 1],[1, 0, 1, 0, 1, 0, 0, 0, 1],[1, 0, 1, 1, 1, 1, 1, 1, 1],[1, 0, 1, 0, 0, 1, 0, 0, 1],[1, 1, 1, 1, 0, 1, 1, 1, 1]
])
# 场地规模
m, n = map.shape
# 设置起点和终点(起点为2,终点为3)
start_x,start_y=0,0
end_x,end_y=1,8
map[start_x, start_y] = 2
map[end_x, end_y] = 3# 使用蒙特卡洛法搜索可行路径及最短路径
trials = 50000 # 蒙特卡罗试验次数
all_paths = [] # 存储所有路径(方向指示)
shortest_path_by_direct = [] # 最短路径(方向指示)
shortest_path_by_pos = [] # 最短路径 (坐标指示)
min_path_len = float('inf') # 最短路径长度#寻找运动反方向的函数
def inverse_direct(x):return {1: 2, 2: 1, 3: 4, 4: 3}[x]for _ in range(trials):x, y = start_x,start_y # 起始点坐标cur_path_by_direct = [] # 当前路径(方向指示)cur_path_by_pos = [(start_x, start_y)] # 当前路径(坐标)len_path = 0 # 当前路径长度last_choice = 0 # 上一次选择visited = np.zeros((m, n), dtype=bool) # 访问记录矩阵visited[x, y] = True # 标记起点为已访问while True:direct = []# 向上if x > 0 and map[x-1, y] != 0 and not visited[x-1, y]:direct.append(1)# 向下if x < m - 1 and map[x+1, y] != 0 and not visited[x+1, y]:direct.append(2)# 向左if y > 0 and map[x, y-1] != 0 and not visited[x, y-1]:direct.append(3)# 向右if y < n - 1 and map[x, y+1] != 0 and not visited[x, y+1]:direct.append(4)if last_choice != 0:ban_opt = inverse_direct(last_choice)if ban_opt in direct:direct.remove(ban_opt)if not direct:break # 无有效方向,跳出循环opt = random.choice(direct)last_choice = opt# 按所选方向前进if opt == 1:x -= 1cur_path_by_direct.append('上')elif opt == 2:x += 1cur_path_by_direct.append('下')elif opt == 3:y -= 1cur_path_by_direct.append('左')elif opt == 4:y += 1cur_path_by_direct.append('右')cur_path_by_pos.append((x, y)) # 更新路径坐标visited[x, y] = True # 标记该点为已访问len_path += 1 # 路径长度加一if map[x, y] == 3: # 遇到终点路径结束if cur_path_by_direct not in all_paths:all_paths.append(cur_path_by_direct)if len_path < min_path_len:min_path_len = len_pathshortest_path_by_direct = cur_path_by_direct.copy()shortest_path_by_pos = cur_path_by_pos.copy()breakprint(f'所有路径:')
print(all_paths)
print(f"路径数量是: {len(all_paths)}")
print("最短路径是:")
print(shortest_path_by_direct)
print(shortest_path_by_pos)
print(f"最短路径长度是: {min_path_len}")# 绘制地图
plt.figure()
for i in range(m):for j in range(n):if map[i, j] == 0:plt.plot(j, i, 'ks', markerfacecolor='k') # 障碍物elif map[i, j] == 2:plt.plot(j, i, 'go', markerfacecolor='g') # 起点elif map[i, j] == 3:plt.plot(j, i, 'ro', markerfacecolor='r') # 终点else:plt.plot(j, i, 'ws') # 可行路径# 绘制最短路径
if shortest_path_by_pos:x_coords, y_coords = zip(*shortest_path_by_pos)plt.plot(y_coords, x_coords, 'b-', linewidth=2)plt.gca().invert_yaxis()
plt.title('路径可视化')
plt.xlabel('列')
plt.ylabel('行')
plt.show()
输出结果
所有路径:
[['右', '右', '下', '下', '下', '右', '右', '右', '下', '下', '右', '右', '右', '上', '上', '上', '上'], ['右', '右', '下', '下', '下', '右', '右', '上', '上', '上', '右', '右', '右', '右', '下'], ['下', '下', '下', '下', '下', '右', '右', '上', '上', '右', '右', '右', '右', '右', '右', '上', '上'], ['下', '下', '下', '下', '下', '右', '右', '上', '上', '右', '右', '上', '上', '上', '右', '右', '右', '右', '下'], ['下', '下', '下', '下', '下', '右', '右', '上', '上', '右', '右', '右', '下', '下', '右', '右', '右', '上', '上', '上', '上'], ['右', '右', '下', '下', '下', '右', '右', '右', '右', '右', '右', '上', '上']]
路径数量是: 6
最短路径是:
['右', '右', '下', '下', '下', '右', '右', '右', '右', '右', '右', '上', '上']
[(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (2, 8), (1, 8)]
最短路径长度是: 13