【Python】递归求解汉诺塔+八皇后问题

题目👇

(1)编写递归代码解答汉诺塔问题:据说古代有一个梵塔,塔内有三个底座A、B、C,A 座上有64 个盘子,盘子大小不等,大的在下,小的在上。有一个和尚想把这64 个盘子从A 座移到C 座,但每次只能允许移动一个盘子。在移动盘子的过程中可以利用B 座,但任何时刻3 个座上的盘子都必须始终保持大盘在下、小盘在上的顺序。如果只有一个盘子,则不需要利用B 座,直接将盘子从A 移动到C 即可。编写函数,接收一个表示盘子数量的参数和分别表示源、目标、临时底座的参数,然后输出详细移动步骤和每次移动后三个底座上的盘子分布情况。

函数定义如下:num表示多少个盘子, src表示原底座‘A’,dst表示目标底座’C’,temp表示中间的临时底座’B’。

底座上的盘子可用列表表示,num个大小不一的盘子可用0~(num-1)这些数字表示,则初始状态下’A’底座的列表为[num-1,num-2,…,2,1,0],’B’底座的列表为空,‘C’底座的列表为空。

        def hannoi(num, src, dst, temp=None):

(2)编写函数,求解八皇后问题。(使用yield)

(3)编写函数,求解八皇后问题。(不使用yield)

解题思路👇

(1)题目要求用列表来表示某底座上有多少个盘子,所以我们放盘子就append在列表末尾加一个元素,拿走盘子就是pop弹出列表最后一个元素。

另外汉诺塔问题的本质就是递归,把问题拆分成三步,第一步是把A上的n-1个盘子移动到B,再把A的最底下的盘子移到C,再把B上的n-1个盘子移到C,如此一来这n-1个盘子也可以想刚才这么移动,就进入了一个递归模式,另外要注意设置递归终止条件,否则栈会爆炸的。

(2)使用回溯法来解决八皇后问题,意思就是一个一个按顺序放置棋子,放置完一个后就去遍历放完这个棋子之后的所有可能,找到符合条件的放置方法直到8个棋子都放完,遍历过后就回溯到上一步,更改上一步的放置方法,继续遍历剩余的可能情况。使用yield来生成题解的序列进而递归生成所有符合条件的题解序列。

(3)思路和(2)相同,同样使用回溯法来解决问题,区别在于不使用yield来生成题解的序列进而递归生成所有符合条件的题解序列而是使用return直接返回。

关于python中yield的用法可以参考这篇博客:python中yield的用法详解——最简单,最清晰的解释_mieleizhi0522的博客-CSDN博客_yield

参考代码👇

#coding:utf-8
#author:Mitchell

#part1:编写递归代码解答汉诺塔问题:据说古代有一个梵塔,塔内有三个底座A、B、C,A 座上有64 个盘子,盘子大小不等,大的在下,小的在上。
#有一个和尚想把这64 个盘子从A 座移到C 座,但每次只能允许移动一个盘子。在移动盘子的过程中可以利用B 座,但任何时刻3 个座上的盘子都必须始终保持大盘在下、小盘在上的顺序。如果只有一个盘子,则不需要利用B 座,直接将盘子从A 移动到C 即可。
#编写函数,接收一个表示盘子数量的参数和分别表示源、目标、临时底座的参数,然后输出详细移动步骤和每次移动后三个底座上的盘子分布情况。
#函数定义如下:num表示多少个盘子, src表示原底座‘A’,dst表示目标底座’C’,temp表示中间的临时底座’B’
#底座上的盘子可用列表表示,num个大小不一的盘子可用0~(num-1)这些数字表示,则初始状态下’A’底座的列表为[num-1,num-2,…,2,1,0],’B’底座的列表为空,‘C’底座的列表为空。
def hannoi(num, src, temp, dst, A, B, C):
    if num==1:
        dst.append(src.pop())
        print(A,'--->',C)
        print(a,b,c)
    else:
        hannoi(num-1,src,dst,temp,A,C,B)
        hannoi(1,src,temp,dst,A,B,C)
        hannoi(num-1,temp,src,dst,B,A,C)

num=int(input('请输入盘子个数:'))
a=[num-i-1 for i in range(num)]
b=[]
c=[]
print(a,b,c)
hannoi(num,a,b,c,'A','B','C')



#part2:编写函数,求解八皇后问题。(使用yield)
#判断函数
def isAllowed(A):
    for i in range(8):
        if sum(A[i])>=2:
            return False
        if sum([A[j][i] for j in range(8)])>=2:
            return False
        if sum([A[i+j][j] for j in range(8-i)])>=2:
            return False
        if sum([A[j][i+j] for j in range(8-i)])>=2:
            return False
        if sum([A[j][i-j] for j in range(i+1)])>=2:
            return False
        if sum([A[i+j][7-j] for j in range(8-i)])>=2:
            return False
    return True

def eight_quene(A,num):
    if num==8:
        yield A
    else:
        for i in range(num,8):
            for j in range(8):
                if A[i][j]==0:
                    A[i][j]=1
                    if not isAllowed(A):
                        A[i][j]=0
                        continue
                    #得到生成器里下一步的所有结果
                    for result in eight_quene(A,num+1):
                        yield result
                    A[i][j]=0
#棋盘初始化
A=[[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0]]
for result in eight_quene(A,0):
    #打印出符合条件的棋盘分布图
    for i in range(8):
        print(result[i])
    print()



#part3:编写函数,求解八皇后问题。(不使用yield)
def eight_quene(A,num):
    if num==8:
        for i in range(8):
            print(A[i])
        print()
    else:
        for i in range(num,8):
            for j in range(8):
                if A[i][j]==0:
                    A[i][j]=1
                    if not isAllowed(A):
                        A[i][j]=0
                        continue
                    eight_quene(A,num+1)#放置对应棋子,继续递归
                    A[i][j]=0   #回溯
#实例化
A=[[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0]]
eight_quene(A,0)

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Mitch311

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

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

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

打赏作者

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

抵扣说明:

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

余额充值