走迷宫-栈和递归版本-Python2.7

本文介绍了两种走迷宫的方法,一种利用栈进行回溯控制,另一种采用递归策略。在迷宫表示为二维数组的情况下,通过尝试错误和回溯找到出口。文中给出了Python2.7的实现代码,并展示了不同方法的输出结果。

方法一:使用栈做回溯控制
在迷宫内的道路只能向上下左右四个方向行走,每次只能走一小步。笔者默认的行走优先级是上、下、左和右(下方左图)。对角的方向不能行走(下方左图)。
在这里插入图片描述
如果遇到墙壁阻挡,就需要尝试剩下几个方向是否有可行的路,继续同样的走法直到找出走出迷宫的路。迷宫的图形用二维数组表示,数组0表示是可以走的路,1代表墙壁。见下图
图
其中,X表示目前的位置,出口在做上角,第一步尝试往上走,此时的位置为
在这里插入图片描述
上图中数字2表示已经走过的路,接着尝试往上走,发现是墙壁,下方是已经走过的路,此时只有左边的路可以走,所以往左走,
在这里插入图片描述
因为我们的假定优先级为先走上,且发现上方有路,所以往上走,接着上方仍然有路,所以接着往上走,此时在右方有路,然后往右走,如下图
在这里插入图片描述
现在惨了,已经没有路可以走了,所以使用回溯的概念,退一步看看有没有其它的路。从上面的迷宫可以知道我们需要连退三步,才会有路可以走
在这里插入图片描述
数字3表示退回的路,现在左方有路可以走,接着上方、右方和下方都是墙壁或者走过的路,所以继续向左走,
在这里插入图片描述
现在一步一步地往上走,就可以找到走出迷宫的路。

这种查询的方法称为“尝试错误”,而一步一步地退回的技巧称为回溯。在写程序时,我们用栈来处理回溯的操作。
下面来看看如何使用栈走迷宫。迷宫问题的迷宫是一个二维数组,如下所示。
在这里插入图片描述
如前描述,数字1代表墙壁,数字0表示可以走。为了简化数组边界的检查,我们在四周都加上了墙壁,所以在编程时不会超出数组的界限,而真正的迷宫只有中间双框的部分。

Python2.7编写

#使用栈走迷宫(回溯)
def find_path(maze):
    x, y = 5, 8 #入口
    path = []
    path.append((x,y))
    while x != 1 or y != 1: #是否是迷宫的出口
        maze[x][y] = 2 #已走过的路
        if maze[x-1][y] <= 0: #往上方走
            x = x - 1
            path.append((x,y)) #存入路径 
        elif maze[x+1][y] <= 0: #往下方走 
            x = x + 1
            path.append((x,y)) #存入路径 
        elif maze[x][y-1] <= 0: #往左方走 
            y = y - 1
            path.append((x,y)) #存入路径 
        elif maze[x][y+1] <= 0: #往右方走 
            y = y + 1
            path.append((x,y)) #存入路径 
        else: #没有路可走:回溯 
            maze[x][y] = 3 #表示回溯的路 
            x,y = path.pop() #退回一步  
            
    maze[x][y] = 2 #最后把出口标示为已走过
    printMaze(maze) #调用打印迷宫的函数
    
#打印迷宫
def printMaze(maze):
    for i in range(1,6):
        for j in range(1,9):
            print "%d" %maze[i][j],
        print "\n"

#主程序:用回溯的方法在数组迷宫找出口
#数字0: 表示是可走的路
#数字1:表示墙壁,不可以走的路 
#数字2:表示走过的路 
#数字3:表示回溯的路 
if __name__ == "__main__":
    #示例迷宫
    maze = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 1, 0, 1, 0, 0, 0, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 1, 1, 1, 0, 0, 1],
            [1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
            [1, 0, 0, 0, 1, 1, 1, 0, 0, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    find_path(maze)

输出:
2 1 3 1 3 3 3 3

2 1 3 1 3 1 1 3

2 1 3 1 1 1 3 3

2 1 2 2 2 2 2 1

2 2 2 1 1 1 2 2

方法二:使用递归找迷宫出口
走迷宫的规则:目前坐标是(i, j),下一步可以行走的路是往上方,下方,左方和右方,如下图
在这里插入图片描述
我们假定优先级为上、下、左和右,也就是说,第一优先是往上走,如果上方可以走就往上走,不行的话尝试第二优先的下方,如果不行再尝试第三优先和第四优先。
我们从入口开始以上述四个方向寻找可以走动的下一个位置,如果找到可以走的位置,就将其值设置为2以表示走过。如果四个方向都不能走,则表示此位置是一条死路,所以必须将其重置为0,继续不断尝试错误找到可行的路径,这就是回溯控制。

Python2.7编写

#使用递归走迷宫
def find_path(x, y):
    if x == 1 and y == 1: #是否是迷宫出口
        maze[x][y] = 2 #记录最后走过的路径
        return 1
    else:
        if maze[x][y] == 0: #是不是可以走
            maze[x][y] = 2 #记录已经走过的路径  
            #调用递归函数:分别是往上、往下、往左和往右
            if find_path(x - 1, y) + find_path(x + 1, y) + find_path(x, y - 1) + find_path(x, y + 1) > 0: 
                return 1
            else:
                maze[x][y] = 0 #此路不通,取消记号
                return 0
        else:
            return 0
    
#打印迷宫
def printMaze(maze):
    for i in range(1,6):
        for j in range(1,9):
            print "%d" %maze[i][j],
        print "\n"

#主程序:用回溯的方法在数组迷宫找出口
#数字0: 表示是可走的路
#数字1:表示墙壁,不可以走的路 
#数字2:表示走过的路 
#数字3:表示回溯的路 
if __name__ == "__main__":
    #示例迷宫
    maze = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 1, 0, 1, 0, 0, 0, 0, 1],
            [1, 0, 1, 0, 1, 0, 1, 1, 0, 1],
            [1, 0, 1, 0, 1, 1, 1, 0, 0, 1],
            [1, 0, 1, 0, 0, 0, 0, 0, 1, 1],
            [1, 0, 0, 0, 1, 1, 1, 0, 0, 1],
            [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
    find_path(5, 8)
    printMaze(maze)

输出
2 1 0 1 0 0 0 0

2 1 0 1 0 1 1 0

2 1 0 1 1 1 0 0

2 1 2 2 2 2 2 1

2 2 2 1 1 1 2 2

前四层的递归调用过程:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值