经典算法之Python实现(一)

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部份为蓝色,则BW的元素对调,而BW必须各+1,表示两个群组都多了一个元素。 

   如果W所在的位置是红色,则将WR交换,但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、老鼠走迷宫

        老鼠走迷宫是递回求解的基本题型,我们在二维阵列中使用2 表示迷宫墙壁,使用 1来表示老
鼠的行走路径,求出由入口至出口的路径。
        
        老鼠的走法有上、下、左、右四个方向,在每前进一格之后就选一个方向前进,无法前进时
退回选择下一个可前进方向,如此在阵列中依序测试四个方向,直到走到出口为止,这是递回的基
本题。
实现如下:
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("")

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

苜蓿花乐园

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

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

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

打赏作者

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

抵扣说明:

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

余额充值