1、河内之塔
河内之塔(Towers of Hanoi)是一个著名的数学和计算机科学问题,它讲述的是将一堆圆盘
从一根柱子移动到另一根柱子,每次只能移动一个圆盘,且大盘子在小盘子之下的原则。
这个问题最早是由法国数学家Edouard Lucas在1883年从泰国带至法国的。据说在创世记
时,Benares有一座波罗教塔,由三支钻石棒所支撑,神在第一根棒上放置了64个由上至下依由小
至大排列的金盘,并命令僧侣将所有的金盘从第一根石棒移至第三根石棒,且搬运过程中遵守大盘
子在小盘子之下的原则,若每日仅搬一个盘子,则当盘子全数搬运完毕之时,此塔将毁损,而也就
是世界末日来临之时。
河内之塔的解法涉及到递归的思想,如果只考虑两个盘子的情况,那么可以直接将一个盘子
从起始柱子移动到目标柱子,再将另一个盘子从起始柱子移动到目标柱子的旁边,然后将第一个盘
子从目标柱子移动到起始柱子的旁边。如果盘子的数量超过了两个,那么可以将其余的盘子视为被
遮住的部分,将其暂时移至视线之外,然后只考虑处理两个盘子的情况,即:A->B、A->C、B->C
这三个步骤。
实现如下:
def hanoi(n, A, B, C):
if n == 1:
print('Move sheet {} from {} to {} \n'.format(n, A, C))
else:
hanoi(n - 1, A, C, B);
print('Move sheet {} from {} to {}\n'.format(n, A, C))
hanoi(n - 1, B, A, C);
if __name__ == '__main__':
n = input('请输入盘数:\n')
hanoi(int(n), 'A', 'B', 'C')
2、费式数列
Fibonacci为1200年代的欧洲数学家,在他的著作中曾经提到:「若有一只兔子每个月生一只
小兔子,一个月后小兔子也开始生产。起初只有一只兔子,一个月后就有两只兔子,二个月后有三
只兔子,三个月后有五只兔子。。。。。。
即:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
费式数列的递推公式为:F(n) = F(n-1) + F(n-2),其中F(1) = F(2) = 1。
实现如下:
def fibonacci(n):
if n <= 0:
return "Invalid input"
elif n == 1:
return [0]
elif n == 2:
return [0, 1]
else:
fib_list = [0, 1]
for i in range(2, n):
fib_list.append(fib_list[i-1] + fib_list[i-2])
return fib_list
if __name__ == '__main__':
n = input('请输入N:\n')
list = fibonacci(int(n))
print(list)
3、三色旗
三色旗的问题最早由E.W.Dijkstra所提出,他所使用的用语为Dutch Nation Flag(Dijkstra为 荷兰人),而多数的作者则使用Three-Color Flag来称之。 假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,您希望 将之分类,并排列为蓝、白、红的顺序,要如何移动次数才会最少,注意您只能在绳子上进行这个动作,而且 一次只能调换两个旗子。 在一条绳子上移动,意味只能使用一个阵列,而不使用其它的阵列来作辅助,问题的解法很简单, 想像一下在移动旗子,从绳子开头进行,遇到蓝色往前移,遇到白色留在中间,遇到红色往后移,如下所示: 如果W所在的位置为白色,则W+1,表示未处理的部份移至至白色群组。 如果W部份为蓝色,则B与W的元素对调,而B与W必须各+1,表示两个群组都多了一个元素。 如果W所在的位置是红色,则将W与R交换,但R要减1,表示未处理的部份减1。 一开始时未处理的R指标会是等于旗子的总数,当R的索引数减至少于W的索引数时,表示接下来的旗子就 都是红色了,此时就可以结束移动。 实现如下:
color = ['r', 'w', 'b', 'w', 'w', 'b', 'r', 'b', 'w', 'r']
wFlag = 0
bFlag = 0
rFlag = len(color) - 1
def swap(x, y):
temp = color[x]
color[x] = color[y]
color[y] = temp
for i in color:
print(i)
while wFlag <= rFlag:
if color[wFlag] == 'w':
wFlag += 1
elif color[wFlag] == 'b':
swap(bFlag, wFlag)
bFlag += 1
wFlag += 1
else:
while wFlag < rFlag and color[rFlag] == 'r':
rFlag -= 1
swap(rFlag, wFlag)
rFlag -= 1
for i in color:
print(i)
4、老鼠走迷宫
maze = [[2, 2, 2, 2, 2, 2, 2], [2, 0, 0, 0, 0, 0, 2], [2, 0, 2, 0, 2, 0, 2], [2, 0, 0, 2, 0, 2, 2],
[2, 2, 0, 2, 0, 2, 2],
[2, 0, 0, 0, 0, 0, 2], [2, 2, 2, 2, 2, 2, 2]]
startI = 1
startJ = 1
endI = 5
endJ = 5
def visit(i, j):
success = 0
maze[i][j] = 1
if i == endI and j == endJ:
success = 1
if success != 1 and maze[i][j + 1] == 0:
visit(i, j + 1)
if success != 1 and maze[i + 1][j] == 0:
visit(i + 1, j)
if success != 1 and maze[i][j - 1] == 0:
visit(i, j - 1)
if success != 1 and maze[i - 1][j] == 0:
visit(i - 1, j)
if success != 1:
maze[i][j] = 0
return success
if __name__ == '__main__':
print("显示迷宫:")
for i in range(7):
for j in range(7):
if maze[i][j] == 2:
print("█ ", end="")
else:
print(" ",end="")
print("")
if visit(startI, startJ) == 0:
print("\n没有找到出口!\n")
else:
print("\n显示路径:\n")
for i in range(7):
for j in range(7):
if maze[i][j] == 2:
print("█",end="")
elif maze[i][j] == 1:
print("◇",end="")
else:
print(" ",end="")
print("\n")
5、骑士之旅
著名的数学游戏“骑士之旅”(Knight's Tour),一个国际象棋的骑士(或者叫马)从棋盘的一
个角落出发,沿着棋盘的边缘行走,每次走一步,并且不能重复经过任何已走过的位置。骑士的走
法,基本上可以使用递回来解决,但是纯綷的递回在维度大时相当没有效率,另一种的解法由J.C.
Warnsdorff在1823年提出,简单的说,先将最难的位置走完,接下来的路 就宽广了,骑士所要走
的下一步,「为下一步再选择时,所能走的步数最少的一步。」,使用这个 方法,在不使用递回
的情况下,可以有较高的机率找出走法(找不到走法的机会也是有的)。
实现如下:
board = [[0]*8,[0]*8,[0]*8,[0]*8,[0]*8,[0]*8,[0]*8,[0]*8];
def travel(x, y):
ktmove1 = [-2, -1, 1, 2, 2, 1, -1, -2]
ktmove2 = [1, 2, 2, 1, -1, -2, -2, -1]
nexti = [0] * 8
nextj = [0] * 8
# 记录出路的个数
exists = [0] * 8
tmpi, tmpj, count, min, tmp = 0, 0, 0, 0, 0
i = x
j = y
board[i][j] = 1
for m in range(2,65):
for l in range(8):
exists[l] = 0
l = 0
for k in range(8):
tmpi = i + ktmove1[k]
tmpj = j + ktmove2[k]
# 边界不可走
if tmpi < 0 or tmpj < 0 or tmpi > 7 or tmpj > 7:
continue
# 可以走
if board[tmpi][tmpj] == 0:
nexti[l] = tmpi;
nextj[l] = tmpj;
# 可走的方向加一个
l += 1
count = l
if count==0:
return 0
elif count==1:
min = 0
else:
for l in range(count):
for k in range(8):
tmpi = nexti[l] + ktmove1[k]
tmpj = nextj[l] + ktmove2[k]
if tmpi < 0 or tmpj < 0 or tmpi > 7 or tmpj > 7:
continue
if board[tmpi][tmpj] == 0:
exists[l] += 1
tmp = exists[0]
min = 0
for l in range(count):
if exists[l] < tmp:
tmp = exists[l]
min = l
i = nexti[min]
j = nextj[min]
board[i][j] = m
return 1
if __name__ == '__main__':
startx = 0
starty = 0
if travel(startx, starty):
print('游历完成')
else:
print('游戏失败')
for i in range(8):
for j in range(8):
print(str(board[i][j]) + ' ', end="")
print("")