Python 递归、迷宫问题、八皇后问题

递归应用场景

  • 各种数学问题,如八皇后问题、汉诺塔、阶乘问题、迷宫问题、球和篮子问题等
  • 各种算法中也会使用到递归,比如快排、归并排序、二分查找、分治算法等
  • 能够用栈解决的问题
  • 递归的优点就是代码比较简洁

迷宫问题(Python版)

迷宫示意图, 红色部分表示墙,绿色部分表示通路,第一张图为初始迷宫,第二张为回溯之后的迷宫

Python 递归、迷宫问题、八皇后问题_第1张图片      Python 递归、迷宫问题、八皇后问题_第2张图片

代码实现

class MiGong:
    def __init__(self):
        # 创建一个 8*7 嵌套列表,模拟迷宫
        self.map = []
        row = 8
        col = 7
        # 初始化迷宫
        # 1表示墙,0表示可通行
        # 将第0行设置为墙
        for i in range(row):
            ls = []
            for j in range(col):
                if i == 0 or i == 7 or j == 0 or j == 6:
                    ls.append(1)
                else:
                    ls.append(0)
            self.map.append(ls)
        self.map[3][1] = 1
        self.map[3][2] = 1
        self.map[4][3] = 1

        self.print_map()

    # 打印迷宫
    def print_map(self):
        row = len(self.map)
        col = len(self.map[0])
        for i in range(row):
            for j in range(col):
                print(self.map[i][j], end=' ')
            print()
        print()

    def find_way(self, i: int, j: int) -> True:
        """
        map: 表示迷宫地图
        (i, j): 老鼠的起始位置
        map[i][j] = 0: 表示该位置没有走过
        map[i][j] = 1: 表示该位置是墙(走不了)
        map[i][j] = 2: 表示该位置是通路(可以走)
        map[i][j] = 3: 表示这个位置是死路上的一个节点(走不了)
        寻路策略:下 -> 右 -> 上 -> 左
        map[6][5] = 2 表示走到了终点(终点位置为(6,5))
        """
        if self.map[6][5] == 2:
            return True
        else:
            if self.map[i][j] == 0:
                # 假设可以走通,先设为2
                self.map[i][j] = 2
                if self.find_way(i + 1, j):  # 向下走
                    return True
                elif self.find_way(i, j + 1):  # 向右走
                    return True
                elif self.find_way(i - 1, j):  # 向上走
                    return True
                elif self.find_way(i, j - 1):  # 向左走
                    return True
                else:  # 死路,走不通,设为3
                    self.map[i][j] = 3
                    return False
            else:  # self.map[i][j] == 1,2,3 ,都表示走不通或已走过
                return False


mg = MiGong()
mg.find_way(1, 1)
mg.print_map()

八皇后问题

思路分析

1、先将第一个皇后放在第一行第一列的位置
2、第二个皇后先放在第二行第一列的位置,然后判断是否冲突,如果冲突,则放在第二行第二列,继续判断,如果冲突,将第二个皇后放在第二行第三列... 依次把第二行所有列都尝试一遍,直到找到合适的一列,摆放第二个皇后
3、接着摆放第三个皇后,依次尝试放在第三行的第一列、第二列、第三列...直到找到一个合适的列摆放第三个皇后
4、同样的摆放第四个、第五个、第六个、第七个、第八个皇后,当第八个皇后也放到第八行的正确位置时,此时找到了一个正确解
5、当第八个皇后摆放好后,即第八个皇后第一次找到正确的位置后,开始回溯,查找其他摆放方法,即将第一个皇后放在第一行第一列这个位置上的所有正确解找出来
6、然后将第一个皇后放在第一行第二列的位置,重复 2-5 的步骤
7、依次将第一个皇后放在第一行第三、四、五、六、七、八列的位置,重复 2-5 的步骤,得到八皇后问题的全部解法(92)

说明:理论上棋盘应该是一个二维数组,但是实际上可以通过算法,用一个一维数组解决,一维数组的下标对应行标,数组的元素对应列标,如 arr[8] = [0, 4, 7, 5, 2, 6, 1, 3] 表示:
    第一个皇后放在第 0 行 第 0 列的位置
    第二个皇后放在第 1 行 第 4 列的位置
    第三个皇后放在第 2 行 第 7 列的位置
    第四个皇后放在第 3 行 第 5 列的位置
    第五个皇后放在第 4 行 第 2 列的位置
    第六个皇后放在第 5 行 第 6 列的位置
    第七个皇后放在第 6 行 第 1 列的位置
    第八个皇后放在第 7 行 第 3 列的位置
即 arr[i] = val 表示第 i 个皇后摆放的位置是第 i 行 第 val 列

代码实现

class Queen:
    count = 0  # 全部的正确解

    def __init__(self, num: int):
        self.num = num  # 皇后的数量
        # 用列表表示一维数组,记录皇后摆放的正确位置
        self.arr = []
        # 初始化数组
        for i in range(num):
            self.arr.append(-1)

    def check_position(self, n: int) -> bool:
        """
        摆放第 n 个皇后在某个位置时,判断是否与前面的 n-1 皇后产生冲突,不冲突返回True
        n 从 0 开始
        """
        for i in range(n):
            # arr[i] = val 表示第 i 个皇后摆放的位置是第 i 行 第 val 列
            if self.arr[i] == self.arr[n]:  # 有两个皇后在同一列
                return False

            # if n - i == self.arr[n] - self.arr[i]:  # 有两个皇后在正对角线上
            #     # 正对角线判断:x2 - x1 == y2 - y1
            #     # (x1, y1) = (i, self.arr[i])
            #     # (x2, y2) = (n, self.arr[n])
            #     return False
            # if n - i == self.arr[i] - self.arr[n]:  # 有两个皇后在反对角线上
            #     # 反对角线上判断:x2 - x1 == y1 - y2
            #     # (x1, y1) = (i, self.arr[i])
            #     # (x2, y2) = (n, self.arr[n])
            #     return False

            # 合并在一起写
            if abs(n - i) == abs(self.arr[n] - self.arr[i]):  # 有两个皇后在对角线上
                return False

        return True

    def place_queen(self, n: int):
        """放置第 n 个皇后,n 从0开始"""
        if n == self.num:  # 全部皇后已经放完,得到一个正确解
            self.count += 1
            print(f'第{self.count}种的解法为{self.arr}')
            return
        # 从第 n 行的第一列开始,依次尝试放置这第 n 个皇后,
        # 看哪个位置可以放,即不会与前面的 n-1 个皇后产生冲突
        for i in range(self.num):  # i 表示列数
            self.arr[n] = i  # 把第 n 个皇后放置在第 n 行第 i 列
            # 检查把第 n 个皇后放置在第 n 行第 i 列后是否与前面的 n-1 个皇后产生冲突
            if self.check_position(n):  # 不产生冲突
                # 如果不产生冲突,则确定了该皇后的放置位置,则开始放置下一个皇后
                self.place_queen(n + 1)

            # 如果冲突,标明第 n 行的第 i 列不能放,继续尝试第 i+1 列

    def print_arr(self):
        """打印数组"""
        for i in self.arr:
            print(i, end=' ')
        print()


q = Queen(8)
q.place_queen(0)  # 从第一个皇后开始,从 0 开始
print('八皇后的全部解法有%s种' % q.count)

你可能感兴趣的:(数据结构和算法,python,数据结构,算法)