第一题:
背景知识
三个正整数a、b、c符合a<c,b<c和a²+b²=c²,我们把这三个正整数叫做一组勾股数。例如3、4、5,3<5, 4<5 和3²+4²=5²。
编程实现
不超过正整数N(10<=N<=1000)的勾股数,即每个数都是不超过N的。
输入描述
正整数N。
输出描述 每行一组勾股数,数字之间用英文逗号分隔。
最后一行是勾股数的组数。
样例输入:
10
样例输出: 6,8,10 3,4,5
2
代码:
·
·
·
·
·
·
·
·
·
·
·
·
N = int(input())rst = [] #结果列表for c in range(N,4,-1): #斜边 for b in range(c-1,1,-1): #长直角边 if 2*b**2 < c**2: #后面的组合不可能了 break for a in range(b,0,-1): if c**2 == b**2 + a**2: rst.append((a,b,c))for item in rst: print(",".join(map(str, item)))print(len(rst))
解说:人为规定直角边的大小顺序,避免重复。
第二题: 背景知识
质数是指大于1的正整数,除了1和本身能整除它外,没有别的正整数能整除它。大于1的正整数,不是质数,那么就是合数。a×b=c, a和b是c的因数,c是a和b的倍数,质数的因数叫做质因数。把一个合数分解为若干个质数的乘积的过程叫做分解质因数。
编程实现
已知正整数N(10<=N<=1000),如果N是合数就直接采用N,否则采用最接近而小于N的合数,然后进行质因数分解。
输入描述
正整数N(10<=N<=1000)。
输出描述 第一行被分解的合数。 第二行全部质因数,用英文逗号分隔,相同因数在因数后小括号标上个数。
样例输入:
13
样例输出: 12
2(2),3
代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
N = int(input())isOdd = N % 2 == 1 #是否是奇数,是可能是质数 zstab = []rst = []sh = Nif isOdd: rN = N - 1 #>=9的偶数,一定是合数 rst2 = [] sh2 = rNfor i in range(2,N//2+1): for zs in zstab: if i % zs == 0: #i是合数 break else: #i是个质数 zstab.append(i) while sh > 1 and sh % i == 0: sh //= i rst.append(i) if sh == 1: #如果N能分解,那没必要再分解最近的小偶数 break if len(rst)==0 and isOdd: while sh2 > 1 and sh2 % i == 0: sh2 //= i rst2.append(i) if sh2 == 1: isOdd = False #已完成
if len(rst) == 0: #如果N是质数,则采用它最近偶数的结果 rst = rst2 N = rNs = set(rst) #去除重复因数 print(N) #打印被分解的合数def pt(n): #打印一项 count = rst.count(n) #计算重复个数 if count > 1: return "{}({})".format(n,count) else: return str(n)print(",".join(map(pt, s))) #打印质因数列表
解说:运用质数筛的同时,分解质因数。
第三题: 编程实现
N(4<=N<=20)个人在N×N的方格中玩游戏,游戏规则是:每个人都要选一个位置使他所在的行、列和对角线(下图中的对角线)上的方格上都没有人。他们可选位置有多少种方案?
例如:4×4的矩阵方格,4个人,有2种可选位置
输入描述
正整数N(4<=N<=20)。
输出描述 可选的位置方案数。
样例输入:
4
样例输出:
2
代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
N = int(input())
def backCheck(queen): (row, col, fatherQueen) = queen while fatherQueen != None: (row1, col1, fatherQueen) = fatherQueen if row1 == row or col1 == col or abs(col-col1) == row-row1: return False return True count = 0
def eightQueens(queen, n): global count if n == N: count += 1 return for col in range(N): nextQueen = n, col, queen if backCheck(nextQueen): eightQueens(nextQueen, n+1) for col in range(N): rootQueen = 0, col, None eightQueens(rootQueen , 1) print(count)
解说:
这是非常常见的“八皇后问题”,要是没学过也不要心慌。拿起我们的法宝——减少条件,编好程序,运行正常后加入被减少的条件,如果原来的程序不适合,重构代码也不难了。 先考虑把N个对象放入N*N矩阵中,没有限制条件,每行1个的方案数。第一行每个位置(用行列二元组)作为根节点,用一个循环调用树叶统计递归函数:
·
·
·
for col in range(N): rootQueen = (0, col) eightQueens(rootQueen , 1) #1但前行数,当=N返回。
递归函数eightQueens要在每行中选一个点,然后下推到下一行,当行数达到N时,计算一个方案,然后返回。代码如下。
·
·
·
·
·
·
·
·
·
·
count = 0
def eightQueens(queen, n): global count if n == N: count += 1 return for col in range(N): nextQueen = (n, col) eightQueens(nextQueen, n+1)
N=4时完整代码如下:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
N = 4
count = 0
def eightQueens(queen, n): global count if n == N: count += 1 return for col in range(N): nextQueen = (n, col) eightQueens(nextQueen, n+1) for col in range(N): rootQueen = (0, col) eightQueens(rootQueen , 1) #1但前行数,当=N返回。 print(count)
运行结果是256,4×4×4×4=256,说明代码没问题。 现在考虑限制条件问题,同行同列这容易,主要是对角线,不过同一对角线上的点横坐标之差和纵坐标之差绝对值相等,反之亦然。 但在上面的代码中,无法知道前面的点的坐标。很自然,每个点除了保持坐标外还至少要知道它前面一个点的引用。这种朝一个方向引用的数据结构就是所谓的“单向链表”。当要生长一个点时,我们可以用递归或循环检查这个点是否符合这三个条件,代码如下:
·
·
·
·
·
·
·
def backCheck(queen): (row, col, fatherQueen) = queen while fatherQueen != None: (row1, col1, fatherQueen) = fatherQueen if row1 == row or col1 == col or abs(col-col1) == row-row1: return False return True
把对象拆为行、列和前一点的引用,在链表中逐点往回比较,直到根节点。
重构代码,加入过滤条件,完成。
第四题: 编程实现
由N(2<=N<=20)盘红花和M(2<=M<=20)盘蓝花围成一个圆圈。有一天,小明闲着没事,研究这些花。他从某个位置开始顺时针数N(1,2,3...,N)后取出该盘花,然后从下一个位置又数N,取出N盘花后,发现取出的都是红花,剩下的都是蓝花。如果规定这个开始位置是1,顺时针是2,3,...N+M,那么蓝花原来摆放在什么位置。
例如:有3盘红花和5盘蓝花构成的圆圈,如下图:
按上面的方法取花,会发现,剩下的都是蓝花,它们的位置是2,4,5,7,8。
输入描述
输入正整数N(4<=N<=20)和M(4<=M<=20),用英文逗号分隔。
输出描述 一行N个整数,代表蓝花原来摆放的位置,用英文逗号分隔。
样例输入:
3,5
样例输出:
2,4,5,7,8
代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
X,Y,K=map(int,input().split(','))lst=[[i+1, True] for i in range(X+Y)]out=0 #出列数index=0 #列表索引count=0 #数数临时变量while out<Y: index%=X+Y #保证列表索引不越界 if lst[index][1]: #未出列 count+=1 #计数加1 if count==K: #计数达到K次 out+=1 #出列数加1 count=0 #恢复计数从下一个对象开始 lst[index][1]=False #当前对象出列 index+=1 #列表索引加1rst=[] #统计剩下的对象位置for item in lst: if item[1]: rst.append(str(item[0]))print(",".join(rst))
解说:这是约瑟夫环,只要在每个对象中保留它的位置,最后剩下的对象中的位置就是开始要在的位置。
第五题: 背景知识 18世纪初普鲁士的哥尼斯堡,有一条河穿过,河上有两个小岛,有七座桥把两个岛与河岸联系起来(如下概述图)。有个人提出一个问题:一个步行者怎样才能不重复、不遗漏地一次走完七座桥,最后回到出发点。后来大数学家欧拉把它转化成一个几何问题——一笔画问题。他不仅解决了此问题,且给出了连通图可以一笔画的充要条件是:奇点的数目不是0个就是2个(连到一点的数目如果是奇数条,就称为奇点;如果是偶数条,就称为偶点。要想一笔画成,必须中间点均是偶点,也就是有来路必有另一条去路,奇点只可能在两端。因此任何图能一笔画成,奇点要么没有,要么在两端) 。
编程实现 已知N(4<=N<=40)个岛之间有架桥,一条桥连接两个岛,所有的桥都用唯一的数字编号。求能否一次不重复走完所有的桥,并指出一条路径。 例:如下图:
它的一条路径是:从1号岛出发,经过3号桥到4号岛,简写为:3(1,3),下同;7(4,2),2(2,1),1(1,2),6(2,3),5(3,1),4(1,3),8(3,4)
输入描述
第一行,一个正整数N(4<=N<=40),表示岛数;
第二行开始的N行按顺序输入每个岛连接的桥,用英文数字隔开。
输出描述 如果不存在这样一条路径,就输出“无”, 否则,输出一条路径(有多条路径的):桥编号和二元组(出发岛编号,终止岛编号),用英文逗号隔开。
样例输入: 4 1,2,3,4,5 1,2,6,7 4,5,6,8
3,7,8
样例输出(参考):
3(1,3),7(4,2),2(2,1),1(1,2),6(2,3),5(3,1),4(1,3),8(3,4)
代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
'''一笔画问题'''#节点,岛和桥的超类class Node: def __init__(self,serNum): #构造岛或桥类,编号 self.serNum=serNum self.nodes= [] #如果是岛,就是连接的桥,否则是一对岛
def link(self, node): #连接岛与桥,把岛加入桥或把桥加入岛 self.nodes.append(node)
islands = [] #岛列表#岛类class Island(Node): passdef initIslands(): #初始化岛 for i in range(N): islands.append(Island(i))
bridges = {} #桥字典#桥类class Bridge(Node): def __init__(self,serNum): Node.__init__(self,serNum) self.hasPassed = False #初始化桥没经过
def initBridges(): #初始化桥 for i in range(N): #遍历岛列表 il = islands[i] for sn in lst[i]: #该岛的输入数据——桥 if sn in bridges: #如果已经在桥字典中,取出 b = bridges[sn] else: #否则生成一个桥对象加入桥列表 b = Bridge(sn) bridges[sn] = b b.link(il) #在桥对象中加入岛 il.link(b) #连接岛与桥
#执行入口def action(start = None, end = None): '''@start 出发点 @end 终止点 无奇点都为None''' rst = [] #走过的桥列表 if start == None: #无奇点连通图,走一条桥后成一对奇点连通图 start = 0 il = islands[start] #岛 b = il.nodes[0] #与岛关联的桥 b.hasPassed = True #出发走一桥 other = b.nodes[1] #与桥相连的第二个岛 if other == il: #如果第二个岛是当前岛,则交换位置后在取第二个岛 b.nodes[1] = b.nodes[0] b.nodes[0] = other other = b.nodes[1] rst.append(b) #结果中加入第一桥 end = start #终点 start = other.serNum #start 和 end是奇点 #执行一对奇点的连通图 go(start, end, rst)
#执行连通图路径检查def go(start, end, rst): '''@start开始位置 @end终点 @rst走过桥列表''' il = islands[start] #岛 for b in il.nodes: #该岛的桥 if b.hasPassed: #如果该桥已经走过,则下一座桥 continue b.hasPassed = True #把该桥设为已经通过状态 rst.append(b) #把该桥加入结果集 if fore(il,b,end,rst): #执行过桥操作,如果成功,返回 return True else: #否则回退 b.hasPassed = False #把该桥通过状态置False rst.remove(b) #结果列表移除该对象 return False #如果该岛没找到可出的桥,回退上一层
#执行过桥操作,如果成功,返回def fore(il,b,end,rst): '''@il出发点岛 @b 要通过的桥 @end 终点岛 @rst结果列表(桥)''' il1 = b.nodes[0] #桥的两头 if il1 == il: #与通过方向相同 il2 = b.nodes[1] else: #方向相反,交换岛的位置 il2 = il1 b.nodes[0] = b.nodes[1] b.nodes[1] = il2 if len(rst) == len(bridges): #走过了所有桥 if il2.serNum == end: #同时到达终点 print(",".join(map(pt, rst))) #打印结果 return True #结束程序 else: #否则,走错路了 return False else: #还没走完所有的桥,继续往下走 return go(il2.serNum, end, rst)
#组织一座桥的字符串def pt(b:Bridge): return "{}({},{})".format(b.serNum, b.nodes[0].serNum+1,b.nodes[1].serNum+1)
#执行块if __name__ == "__main__": N = int(input()) lst = [set(map(int, input().split(","))) for i in range(N) ] #岛与桥 #统计奇点 oddS = [] for i in range(N): if len(lst[i]) % 2 > 0: oddS.append(i) oddL = len(oddS) #奇点数 #欧拉定理:一个连通图中,要么无奇点,要么只有两个奇点, #否则不能一笔画,两个奇点的起点和终点一定是这2个奇点。 if oddL != 0 and oddL != 2: print("无") else: initIslands() #初始化岛 initBridges() #初始化桥 if oddL == 2: #如果有2个奇点,从一个出发,终于第二个奇点 action(oddS[0], oddS[1]) else: #如果无奇点,从任意一点出发回到这点 action()
解说: 一笔画问题与其它连通图问题有所不同,因为它是要一次通过所有的桥(连接)。岛与岛之间的桥(连接)实际也是一种节点(只有2个连接,对方都是岛)。这样一笔画问题就进一步抽象为这样的连通图:图中有2类节点,一类只有可连接多个不同类的节点但不能连接同类节点,所谓的“岛”;而另一类只能连接2个第一类节点。问题转化为一次经过所有第二类节点。示例的拓扑图就转化为(岛用圆,桥用四边形):
两种节点有共同的属性:编号和另类节点列表(需要link方法关联它们),桥有一个属性标志该桥是否已经走过,因此它们的类结构如下:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
#节点,岛和桥的超类class Node: def __init__(self,serNum): #构造岛或桥类,编号 self.serNum=serNum self.nodes= [] #如果是岛,就是连接的桥,否则是一对岛
def link(self, node): #连接岛与桥,把岛加入桥或把桥加入岛 self.nodes.append(node) #岛类class Island(Node): pass#桥类class Bridge(Node): def __init__(self,serNum): Node.__init__(self,serNum) self.hasPassed = False #初始化桥没经过
由于不可能同时创建岛和桥并使它们连接在一起,因此先创建只有编号的岛放在列表中。桥的数据分散在岛中,为了保持桥数据的唯一性,用字典保持桥数据。初始化代码如下:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
islands = [] #岛列表def initIslands()->None: #初始化岛 for i in range(N): islands.append(Island(i))
bridges = {} #桥字典def initBridges(): #初始化桥 for i in range(N): #遍历岛列表 il = islands[i] for sn in lst[i]: #该岛的输入数据——桥 if sn in bridges: #如果已经在桥字典中,取出 b = bridges[sn] else: #否则生成一个桥对象加入桥列表 b = Bridge(sn) bridges[sn] = b b.link(il) #在桥对象中加入岛 il.link(b) #连接岛与桥
首先我们要明确,无奇点和一对奇点的差别就是多了一座桥,因此对于无奇点的情况,只有先走一座桥,就转化为一对奇点的情况:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
#执行入口def action(start = None, end = None): '''@start 出发点 @end 终止点 无奇点都为None''' rst = [] #走过的桥列表 if start == None: #无奇点连通图,走一条桥后成一对奇点连通图 start = 0 il = islands[start] #岛 b = il.nodes[0] #与岛关联的桥 b.hasPassed = True #出发走一桥 other = b.nodes[1] #与桥相连的第二个岛 if other == il: #如果第二个岛是当前岛,则交换位置后在取第二个岛 b.nodes[1] = b.nodes[0] b.nodes[0] = other other = b.nodes[1] rst.append(b) #结果中加入第一桥 end = start #终点 start = other.serNum #start 和 end是奇点 #执行一对奇点的连通图 go(start, end, rst)
然后,我们用递归回退方法寻找路径(即发现路径错了就回退)。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
#执行连通图路径检查def go(start, end, rst): '''@start开始位置 @end终点 @rst走过桥列表''' il = islands[start] #岛 for b in il.nodes: #该岛的桥 if b.hasPassed: #如果该桥已经走过,则下一座桥 continue b.hasPassed = True #把该桥设为已经通过状态 rst.append(b) #把该桥加入结果集 if fore(il,b,end,rst): #执行过桥操作,如果成功,返回 return True else: #否则回退 b.hasPassed = False #把该桥通过状态置False rst.remove(b) #结果列表移除该对象 return False #如果该岛没找到可出的桥,回退上一层
最后,解决过桥问题。如果桥中的岛数据方向与过桥的方向不同,需要调换。如果到达点终点,则结束。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
#执行过桥操作,如果成功,返回def fore(il,b,end,rst): '''@il出发点岛 @b 要通过的桥 @end 终点岛 @rst结果列表(桥)''' il1 = b.nodes[0] #桥的两头 if il1 == il: #与通过方向相同 il2 = b.nodes[1] else: #方向相反,交换岛的位置 il2 = il1 b.nodes[0] = b.nodes[1] b.nodes[1] = il2 if len(rst) == len(bridges): #走过了所有桥 if il2.serNum == end: #同时到达终点 print(",".join(map(pt, rst))) #打印结果 return True #结束程序 else: #否则,走错路了 return False else: #还没走完所有的桥,继续往下走 return go(il2.serNum, end, rst)
第六题: 汉诺塔(Tower of Hanoi),又称河内塔,是一个源于印度古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
小明用海龟画图制作了一个7层汉诺塔的游戏,代码如下,但小明不会递归函数move怎么编,请你补全程序,使游戏能走起来。
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
'''以递归加栈的方式实现汉诺塔算法'''import turtle as t #导入海龟画图并把它重命名为timport time #导入时间模块#初始化海龟t.title("递归汉诺塔——学思营https://xuesiying.stem86.com") #设置标题t.setup(500, 500) #把窗口初始化t.screensize(400, 400) #画布大小
#数据节点class Node: def __init__(self, value): #节点初始化 self.value = value #节点的值 self.pre = None #指向前一个节点的指针 #栈class Stack: def __init__(self, name=None, location=None): #栈初始化 ''' @name为栈名 @location为初始位置 ''' self.point = None #定义栈顶指针 self.length = 0 #栈中节点总数 self.name = name self.location =location def push(self, value): #向栈中压入数据方法 node= Node( value) #把压入栈中的数据包装成栈节点 if self.point != None: #假如栈顶指针不为空 node.pre = self.point #后压入栈的节点指向前一个节点 self.point = node #栈顶指针指向新压入栈的新节点 else: #假如栈顶指针为空 self.point = node #栈顶指针指向栈中唯一的节点 self.length += 1 #栈中总数加1 add(self, node) #加入海龟 def pop(self): #从栈中弹出数据方法 if self.point != None: #假如栈顶指针不为空 node = self.point #获得栈顶指针指向的节点 self.point = node.pre #栈顶指针向前一个节点移动 node.pre = None #把栈顶节点的向前指针置为空 self.length -= 1 #栈中节点总数减1 div(self, node) #减一节点 return node.value #返回弹出节点的值 else: #如果栈内没有节点 return None #返回空 def isNone(self): #栈的判空方法 if self.length>0: #假如栈内节点总数大于0 return False #返回False else: #假如栈内节点总数等于0 return True #返回True
#加入海龟def add(stack, node): stack.location = stack.location[0], stack.location[1]+25 #y坐标上一台阶 node.value.st() node.value.setpos(stack.location) #移动海龟 #减1海龟def div(stack, node): stack.location = stack.location[0], stack.location[1]-25 #y坐标下一台阶 node.value.ht()
#递归,层层分解def move(n, s1, s2, s3): ''' @n 塔的层数 @s1 原塔 @s2 中间塔 @s3 目的塔 ''' //这里补全程序
t.up() #提笔
posA=(-100, -100) #A塔位置t.setpos(posA[0],posA[1]) #A塔写上标签At.write("A", align="center", font=("黑体", 14, "normal")) #居中14号a = Stack('A', posA) #声明1个栈——第1根柱子起名叫A
posB=(0, -100)t.setpos(posB[0],posB[1])t.write("B", align="center", font=("黑体", 14, "normal"))b = Stack('B', posB) #声明b柱子posC=(100, -100)t.setpos(posC[0],posC[1])t.write("C", align="center", font=("黑体", 14, "normal"))c = Stack('C', posC) #声明c柱子 t.shape("square") #采用正方形海龟t.seth(90) #海龟朝上t.speed(3) #海龟慢速移动
print("海龟画图初始化完成,3秒后构建7层汉诺塔。")time.sleep(3) #暂停3秒
temp = t.clone() #克隆海龟 最大的碟子,黑色temp.shapesize(5, 0.5, 1) #横向5倍,同向0.5, 边框1a.push(temp) #加入A栈
temp = t.clone()temp.shapesize(4.5, 0.5, 1)temp.fillcolor("#FF0000") #填充颜色temp.pencolor("#FF0000") #画笔颜色a.push(temp)
temp = t.clone()temp.shapesize(4, 0.5, 1)temp.fillcolor("#FFFF00")temp.pencolor("#FFFF00")a.push(temp)
temp = t.clone()temp.shapesize(3.5, 0.5, 1)temp.fillcolor("#00FF00")temp.pencolor("#00FF00")a.push(temp)
temp = t.clone()temp.shapesize(3, 0.5, 1)temp.fillcolor("#00FFFF")temp.pencolor("#00FFFF")a.push(temp)
temp = t.clone()temp.shapesize(2.5, 0.5, 1)temp.fillcolor("#0000FF")temp.pencolor("#0000FF")a.push(temp)
temp = t.clone()temp.shapesize(2, 0.5, 1)temp.fillcolor("#FF00FF")temp.pencolor("#FF00FF")a.push(temp)
t.ht() #隐藏海龟print("7层汉诺塔初始化完成,3秒后移动。")time.sleep(3)
n = a.lengthmove(n, a, b, c)
结果视频:
,时长00:31
输入描述
无
输出描述 程序能运行与视频相符。
代码:
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
·
#递归,层层分解def move(n, s1, s2, s3): ''' @n 塔的层数 @s1 原塔 @s2 中间塔 @s3 目的塔 ''' if n != 1: move(n-1, s1, s3, s2) #把底座上面所有盘子移动到中间柱子上 move(1, s1, s2, s3) #移动底座盘子到目标柱上 move(n-1,s2, s1, s3) #把中间柱子上的盘子移动到目标柱子上 else: #当只剩一个盘子时 #s1 -> s3 s3.push(s1.pop()) #把盘子移动到目标柱子上 print(s1.name, '=>', s3.name) #打印移动盘
解说:当只有一个盘子,只需从源塔到目标塔(递归返回条件)——move(1, s1,s2,s3);当多于1个盘子时,就要先把它上面的盘子先移到中间塔——move(n-1,s1,s3,s2);然后再把中间塔的盘子移到目标塔——move(n-1,s2,s1,s3)。这个过程貌似违反规则,但由于是递归,实际过程是合规的。
参见免费资源:
Python数据结构与算法——第八课 汉诺塔