一、目的
- 正确应用蛮力法求解迷宫问题。
- 对边界值测试结果。
- 正确分析算法时间复杂度。
二、实验内容与设计思想
设计思路
(1) 输入迷宫规模n
(2) 随机生成n×n迷宫地图
(3) 深度遍历走迷宫
(4) 输出迷宫
主要数据结构
结构名 | 数据结构 | 参数介绍&&方法 |
point类 | class Point(): def __init__(self, x, y): self.x = x self.y = y | 参数介绍: x,y代表在迷宫内的位置 方法 point方法,输出位置 |
Maze类 | class Maze(): def __init__(self): self.start = Point(0, 0) self.maze = [] self.n = 5 self.road = [] self.correct_road = [] | 参数介绍 start:迷宫开始位置 maze:迷宫 n:迷宫的规模 road:路径 correct_road:所有可以走到重点的路径集合 方法 get_maze:获取随机迷宫 get_maze_prob: 获取随机迷宫(获得0的概率0.7) print:输出路径 go:实现迷宫探索 main:主方法 |
主要代码结构
三、实验使用环境
软件:Python 3.9.7
PyCharm 2021.3.1
平台:win10
四、实验步骤和调试过程
4.1 生成迷宫
参数
输入:n------迷宫的规模
输出:无
步骤
使用random.randint函数生成n行n列的迷宫,并打印出来。
测试
-
测试点1:1-10: 随机抽取10个
-
测试点2:-100-100:随机抽取10个
-
测试点3:-1000-1000:随机抽取10个
<img src="http://akavjht.top/image/0022/image6.png"width=“15px” style=“width:15px;”> 结果
请输入迷宫的大小:-999
请重新输入
请输入迷宫的大小:0
请重新输入
请输入迷宫的大小:9
迷宫为:
[0, 0, 0, 0, 1, 1, 0, 0, 1]
[0, 0, 1, 1, 1, 1, 0, 0, 1]
[0, 1, 0, 0, 0, 1, 1, 1, 0]
[1, 0, 1, 1, 0, 1, 1, 0, 1]
[0, 0, 0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 1, 0, 1, 1, 0, 0]
[0, 0, 1, 1, 0, 0, 0, 0, 1]
[1, 0, 1, 1, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 0]
请输入迷宫的大小:15
迷宫为:
[0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0]
[0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0]
[1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0]
[1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0]
[1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0]
[1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]
[0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
[0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0]
仅展示部分结果,完整测试数据在"附件1"中。
4.2 深度遍历迷宫
参数
输入:
point------现在所在的位置
输出:
无
步骤
步骤说明:
判断现在的位置是否在终点
如果在终点:
将本路径添加到correct_road,删除最后一个位置,结束
否则:
向下一个位置探索,判断下一个位置是否能走
如果能走:
将下一个点添加到路径
Go(下一个点)
否则:
向下一个方向探索直到没有方向
在路径中删除现在的位置,结束
流程图:
代码:
def go(self, point):
x, y = point
if x == self.n - 1 and y == self.n - 1:
self.correct_road.append(self.road.copy())
del self.road[-1]
return
direction = [DIRECTION.DOWN.value, DIRECTION.RIGHT.value, DIRECTION.LEFT.value, DIRECTION.UP.value]
self.maze[x][y] = 1
for i in range(4):
point = Point(x + direction[i][0], y + direction[i][1])
x_new, y_new = point.point()
if x_new < 0 or y_new < 0 or x_new >= self.n or y_new >= self.n:
continue
if self.maze[x_new][y_new] == 0:
self.road.append(point.point())
self.go(point.point())
self.maze[x][y] = 0
del self.road[-1]
4.3 输出迷宫路径
参数
输入:无
输出:无
步骤
- 输出路径的数量
- 挨个输出路径
<img src="http://akavjht.top/image/0022/image5.png"测试
-
测试点1:1-10: 随机抽取10个
-
测试点2:-100-100:随机抽取10个
-
测试点3:-1000-1000:随机抽取10个
结果
请输入迷宫的大小:10
迷宫为:
[0, 1, 1, 0, 0, 1, 1, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 1, 1]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 0, 0, 1, 1, 0, 1, 0, 1]
[1, 1, 1, 1, 0, 1, 0, 0, 1, 0]
[1, 0, 0, 1, 1, 0, 1, 0, 1, 1]
[0, 0, 1, 0, 0, 0, 1, 0, 1, 0]
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0]
迷宫有0条路径
迷宫为:
[0, 0, 0, 1, 1]
[0, 0, 1, 0, 1]
[0, 1, 0, 1, 0]
[0, 0, 1, 0, 1]
[1, 0, 0, 0, 0]
迷宫有2条路径
[0, 0] [0, 1] [1, 1] [1, 0] [2, 0] [3, 0] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
[0, 0] [1, 0] [2, 0] [3, 0] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
请输入迷宫的大小:7
迷宫为:
[0, 0, 1, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 1, 1]
[0, 0, 0, 1, 1, 0, 1]
[1, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 0]
[0, 0, 1, 0, 1, 1, 0]
[1, 0, 0, 0, 1, 0, 0]
迷宫有28条路径
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [3, 3] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [3, 2] [3, 1] [4, 1] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [3, 2] [3, 3] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [3, 2] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [3, 2] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [4, 1] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [4, 1] [4, 2] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [1, 2] [2, 2] [2, 1] [3, 1] [4, 1] [4, 2] [3, 2] [3, 3] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [3, 3] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [2, 2] [3, 2] [3, 1] [4, 1] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [3, 2] [3, 3] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [3, 2] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [3, 2] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [4, 1] [4, 2] [4, 3] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [4, 1] [4, 2] [4, 3] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [4, 1] [4, 2] [3, 2] [3, 3] [3, 4] [4, 4]
[0, 0] [0, 1] [1, 1] [2, 1] [3, 1] [4, 1] [4, 2] [3, 2] [3, 3] [4, 3] [4, 4]
迷宫为:
[0, 1, 0, 1, 0]
[1, 0, 0, 1, 0]
[1, 0, 0, 0, 0]
[0, 1, 0, 0, 0]
[1, 0, 0, 0, 0]
迷宫有0条路径
仅展示部分结果,完整测试数据在"附件1"中。
4.4 改良
问题
经过测试发现,迷宫的探索结果倾向于0条,因为迷宫的构成是随机获取0和1。
解决方法
对生成迷宫的函数进行改进,对迷宫的每个位置按照0.7:0.3的概率生成0和1。
将0的概率作为输入,所以0.7这个数值是可以改变的。
4.5 时间复杂度
4是4个方向,n×n是迷宫的规模
- 最坏情况下:O(n2)
O(4(n2-1)) :除了终点,每个点在四个方向都探索一遍
- 最好情况O(1)
O(4):在(0,0)四个方向都没办法走
- 所以算法的时间复杂度为O(n2)
200次迷宫探索时间图
4.6 空间复杂度
深度搜索算法是一个递归算法,需要借助一个递归工作栈,所以的空间复杂度是O(n2)
五、附录
迷宫探索
import numpy as np
from enum import Enum
import copy
class DIRECTION(Enum):
UP = [0, -1]
DOWN = [0, 1]
LEFT = [-1, 0]
RIGHT = [1, 0]
class Point():
def __init__(self, x, y):
self.x = x
self.y = y
def point(self):
return [self.x, self.y]
class Maze():
def __init__(self):
self.start = Point(0, 0)
self.maze = []
self.n = 5
self.road = []
self.correct_road = []
def get_maze(self, n):
self.maze = np.random.randint(0, 2, (n, n))
self.maze[0][0] = self.maze[n - 1][n - 1] = 0
print("迷宫为:")
for i in self.maze:
print(i)
def get_maze_prob(self, n, prob):
for i in range(n):
line = []
for j in range(n):
line.append(np.random.choice([0, 1], p=[prob, 1 - prob]))
self.maze.append(line)
self.maze[0][0] = self.maze[n - 1][n - 1] = 0
print("迷宫为:")
for i in self.maze:
print(i)
def print(self):
print("迷宫有%d条路径" % len(self.correct_road))
for i in self.correct_road:
for j in i:
print(j, " ", end="")
print()
def go(self, point):
x, y = point
if x == self.n - 1 and y == self.n - 1:
self.correct_road.append(self.road.copy())
del self.road[-1]
return
direction = [DIRECTION.DOWN.value, DIRECTION.RIGHT.value, DIRECTION.LEFT.value, DIRECTION.UP.value]
self.maze[x][y] = 1
for i in range(4):
point = Point(x + direction[i][0], y + direction[i][1])
x_new, y_new = point.point()
if x_new < 0 or y_new < 0 or x_new >= self.n or y_new >= self.n:
continue
if self.maze[x_new][y_new] == 0:
self.road.append(point.point())
self.go(point.point())
self.maze[x][y] = 0
del self.road[-1]
def main(self, n):
self.get_maze_prob(n, 0.7)
self.road.append(self.start.point())
self.go(self.start.point())
self.print()
if __name__ == "__main__":
while True:
n = int(input("请输入迷宫的大小:"))
if n <= 0:
print("请重新输入")
else:
break
Maze().main(n)