解决“迷宫”问题

# 第一种:使用回溯法的子集树模版实现
#定义迷宫布局,1表示墙壁,0表示可通行的路径,这里是一个8行10列的迷宫示例
maze = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
        [0, 0, 1, 0, 1, 1, 1, 1, 0, 1],
        [1, 1, 0, 1, 0, 1, 1, 0, 1, 1],
        [1, 0, 1, 1, 1, 0, 0, 1, 1, 1],
        [1, 1, 1, 0, 0, 1, 1, 0, 1, 1],
        [1, 1, 0, 1, 1, 1, 1, 1, 0, 1],
        [1, 0, 1, 0, 0, 1, 1, 1, 1, 0],
        [1, 1, 1, 1, 1, 0, 1, 1, 1, 1]]

# 迷宫的行数和列数
m, n = 8, 10
# 迷宫入口坐标,这里表示第2行第1列(索引从0开始)
entry = (1, 0)
# 用于记录一个解(路径),初始化为包含入口坐标的列表
path = [entry]
# 用于存储所有找到的解(路径集合)
paths = []
# 移动的方向(顺时针8个:北(N),东北(EN),东(E),东南(ES),南(S),西南(WS),西(W),西北(WN))
# 每个元组表示在行列上的偏移量,例如 (-1, 0) 表示向上移动一格(行减1,列不变)
directions = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]


# 检查坐标 (nx, ny) 是否冲突(即是否越界或者是墙壁)
def conflict(nx, ny):
    global m, n, maze
    # 判断坐标是否在迷宫范围内(行和列都要满足大于等于0且小于迷宫的行数和列数)
    # 并且对应位置的值为0(表示可通行),如果满足条件则返回False,表示没有冲突
    if 0 <= nx < m and 0 <= ny < n and maze[nx][ny] == 0:
        return False
    return True


# 递归函数,用于在迷宫中探索可行路径
def walk(x, y):
    global entry, m, n, maze, path, paths, directions
    # 判断当前位置是否不是入口并且是否到达了迷宫的边界(行或列索引是最后一行或最后一列)
    # 如果是,则将当前路径path添加到paths列表中,表示找到了一条可行路径
    if (x, y)!= entry and (x % (m - 1) == 0 or y % (n - 1) == 0):
        paths.append(path[:])
    else:
        # 遍历所有的移动方向
        for d in directions:
            # 根据当前方向计算下一个位置的坐标
            nx, ny = x + d[0], y + d[1]
            # 将下一个位置坐标添加到当前路径path中,表示尝试往这个方向走
            path.append((nx, ny))
            # 检查下一个位置是否没有冲突(即可通行)
            if not conflict(nx, ny):
                # 如果可通行,将该位置标记为已走过(这里标记为2,方便后续区分)
                maze[nx][ny] = 2
                # 递归调用walk函数,继续从新位置探索路径
                walk(nx, ny)
                # 探索完该位置后,将其标记恢复为0(可通行状态),以便下次探索其他路径时可以再次经过
                maze[nx][ny] = 0
                # 将刚刚添加的位置坐标从当前路径path中移除,回溯到上一个位置,尝试其他方向
                path.pop()


# 用于展示给定路径在迷宫中的情况,同时打印原始迷宫和标记了路径后的迷宫
def show(path):
    global maze
    import pprint, copy
    # 深拷贝原始迷宫,用于标记路径后展示,不影响原始迷宫数据
    maze2 = copy.deepcopy(maze)
    for p in path:
        # 在拷贝的迷宫中,将路径上的位置标记为2
        maze2[p[0]][p[1]] = 2
        # 打印原始迷宫布局
        pprint.pprint(maze)
        print()
        # 打印标记了路径后的迷宫布局
        pprint.pprint(maze2)


# 从入口位置 (1, 0) 开始在迷宫中探索路径
walk(1, 0)
# 判断是否找到了路径,如果找到了则进行后续操作(打印路径和展示路径在迷宫中的情况)
if paths:
    print(paths[-1], '\n')
    show(paths[-1])
else:
    print("没有找到可行的迷宫路径")


# 第二种:使用矩阵标记移动路径

class Maze():
    def __init__(self):
        """
        类的构造函数,用于初始化迷宫相关的属性,这里将迷宫的边长属性N初始化为4,表示处理的是一个4x4的迷宫(示例情况)。
        """
        self.N = 4

    def printSolution(self, sol):
        """
        以清晰易读的格式打印出迷宫的解(路径)情况。
        参数sol是一个二维列表,其中用1表示路径上的位置,0表示不在路径上的位置,以此来展示整个迷宫中可行的路径布局。

        该函数通过两层嵌套的for循环遍历二维列表sol,逐行逐列地打印出每个元素,元素之间用空格隔开,每行结束后进行换行操作。
        """
        for i in range(self.N):
            for j in range(self.N):
                print(sol[i][j], end=' ')
            print()

    def isSafe(self, maze, x, y):
        """
        检查给定坐标 (x, y) 在迷宫中是否是安全可通行的位置。

        参数:
        - maze: 二维列表,表示整个迷宫的布局,其中1表示可通行的位置(比如通道),0表示不可通行的位置(比如墙壁)。
        - x, y: 待检查的位置坐标,其坐标值的范围应该在迷宫的边长范围内。

        返回值:
        - 如果坐标 (x, y) 满足以下所有条件,则返回True,表示该位置是安全可通行的;否则返回False:
            - x坐标大于等于0且小于迷宫的边长self.N。
            - y坐标大于等于0且小于迷宫的边长self.N。
            - 迷宫中对应坐标位置的元素值为1,即表示该位置是可通行的。
        """
        return x >= 0 and x < self.N and y >= 0 and y < self.N and maze[x][y] == 1

    def getPath(self, maze, x, y, sol):
        """
        通过递归回溯的方式尝试在迷宫中寻找从起点 (0, 0) 到终点 (self.N - 1, self.N - 1) 的可行路径。

        参数:
        - maze: 二维列表,代表整个迷宫的布局,元素值1和0分别表示可通行与不可通行位置。
        - x, y: 当前正在探索的位置坐标,初始时为起点坐标 (0, 0),在递归过程中会不断更新。
        - sol: 二维列表,用于记录在探索过程中发现的路径情况,初始化为全部元素为0的列表,若某个位置在找到的路径上,则对应元素会被标记为1。

        返回值:
        - 如果成功找到从起点到终点的路径,返回True;如果经过所有尝试后仍未找到可行路径,则返回False。
        """
        if x == self.N - 1 and y == self.N - 1:
            sol[x][y] = 1
            return True
        if self.isSafe(maze, x, y):
            sol[x][y] = 1
            # 优先尝试向右移动一格(y坐标增加1)来探索路径
            if self.getPath(maze, x, y + 1, sol):
                return True
            # 若向右探索无果,再尝试向下移动一格(x坐标增加1)来探索路径
            if self.getPath(maze, x + 1, y, sol):
                return True
            sol[x][y] = 0
            return False
        return False
if __name__ == "__main__":
    rat = Maze()
    # 定义一个4x4的迷宫布局示例,其中1表示可通行位置,0表示不可通行位置(如墙壁等)
    maze = [[1, 0, 0, 0],
            [1, 1, 0, 1],
            [0, 1, 0, 0],
            [1, 1, 1, 1]]
    # 初始化用于记录路径情况的二维列表,初始所有位置都标记为0,表示尚未探索到路径经过这些位置
    sol = [[0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0]]
    if not rat.getPath(maze, 0, 0, sol):
        print("不存在可达路径!")
    else:
        rat.printSolution(sol)

返回结果:
第一种:
 

第二种:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luky!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值