Python进阶之八皇后算法

1. 理解算法前提

1.1 理解递归

递归:recursion

简单来说就是引用(或者调用)自身的意思。用递归实现的功能都可以用循环实现,但是有些时候递归函数更易读

# 通过循环实现幂函数
def power(x, n):
    result = 1
    for i in range(n):
        result *= x
    return result


# 通过递归实现幂函数
def power(x, n):
    if n == 0:
        return 1
    else:
        # 注意此时调用power函数时的输入:x, n-1
        # 如果是输入: x, n 该函数将会陷入无限循环, 直到运行崩溃
        return x * power(x, n-1)

递归函数一定要以一个最小可能性问题结束,上述代码中的最小可能性问题就是:n == 0

1.2 Python生成器

关键字:yield

任何包含yield语句的函数称为生成器

生成器的行为和普通函数有很大的区别,它不像return那样返回值,而是每次产生多个值。每次产生一个值(使用yield语句),函数就会被冻结:即函数停在那点等待被重新唤醒。函数被重新唤醒后就从停止的那点开始执行。

# 定义一个递归生成器
# 问题描述:按从左到右的顺序取出序列中的每个元素,不论该序列内部嵌套了多少层序列
# 此处忽略输入为字符串的序列,我们测试的时候用列表
def flatten(nested):
    try:
        for sublist in nested:
            for element in flatten(sublist):
                yield element
    except:
        yield nested


# 调用该生成器
list(flatten([[[1],2],3,4,[5,[6,7]],8]))

# 测试一下返回的到底是啥
g = flatten([[[1],2],3,4,[5,[6,7]],8])
print(g)
while(True):
    try:
        print(next(g))
    except:
        break

通过上述演示,我们可以看到生成器调用结束后返回了一个生成器对象,通过next函数可以逐个获取生成器内的每个返回值

如果上述递归生成器改成普通函数,则需要一个额外的序列去存储每次生成的element

2. 八皇后算法

2.1 八皇后问题描述

在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法

2.2 算法核心

2.2.1 检测冲突

def conflict(state, nextX):
    '''检测冲突, 逻辑如下
       state = (y1, y2, y3, ...)
       第一个皇后的位置: (0,y1)
       第二个皇后的位置: (1,y2)
       第三个皇后的位置: (2,y3)
       依此类推
       nextX 是下一个皇后的位置的x坐标, 从0开始
    '''
    # nextY 是下一个皇后的位置的y坐标, 从0开始, 于是: nextY = len(state)
    nextY = len(state)
    # 循环已知的皇后
    for i in range(nextY):
        # state[i] 是前面的皇后的位置的x坐标, i=0表示第一个皇后, i=1表示第二个皇后, 依次类推
        # 下一个皇后和前面任意一个皇后的位置的x坐标不能相同(同列), x坐标距离和y坐标距离不能相等(同斜线)
        if abs(nextX - state[i]) in (0, nextY - i):
            return True
    return False

2.2.2 基于Python生成器求解

def queens(num=8, state=()):
    # 从第一列判断到第num-1列
    for pos in range(num):
        # 不冲突
        if not conflict(state, pos):
            # 已经是最后一个皇后了
            if len(state) == num-1:
                # 返回此皇后的位置
                yield (pos,)
            else:
                # 递归获取下一个皇后的位置, 输入为:下一行列数, 前面皇后的位置信息
                for result in queens(num, state + (pos,)):
                    # 返回此皇后的位置 + 后面几个皇后的位置, 因为是递归, 所以是此皇后的放前面
                    yield (pos,) + result

2.2.3 输出结果并图形化输出摆法

def prettyprint(solution):
    def line(pos, length=len(solution)):
        print((' - ' * pos) + ' x ' + (' - ' * (length - pos - 1)))
    print(solution)
    for pos in solution:
        line(pos)

# 输出摆法
print(len(list(queens(4))))

# 优化输出结果
for solution in queens(4):
    prettyprint(solution)

Congratulations

恭喜你学习到了第一个用Python实现的经典回溯算法——八皇后问题,更多进阶内容请继续关注,感兴趣记得订阅哦!!!

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

刺客码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值