首页 > 试题广场 >

迷宫寻路

[编程题]迷宫寻路
  • 热度指数:16708 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 128M,其他语言256M
  • 算法知识视频讲解
假设一个探险家被困在了地底的迷宫之中,要从当前位置开始找到一条通往迷宫出口的路径。迷宫可以用一个二维矩阵组成,有的部分是墙,有的部分是路。迷宫之中有的路上还有门,每扇门都在迷宫的某个地方有与之匹配的钥匙,只有先拿到钥匙才能打开门。请设计一个算法,帮助探险家找到脱困的最短路径。如前所述,迷宫是通过一个二维矩阵表示的,每个元素的值的含义如下 0-墙,1-路,2-探险家的起始位置,3-迷宫的出口,大写字母-门,小写字母-对应大写字母所代表的门的钥匙

输入描述:
迷宫的地图,用二维矩阵表示。第一行是表示矩阵的行数和列数M和N
后面的M行是矩阵的数据,每一行对应与矩阵的一行(中间没有空格)。M和N都不超过100, 门不超过10扇。


输出描述:
路径的长度,是一个整数
示例1

输入

5 5
02111
01a0A
01003
01001
01111

输出

7
像求助一下,用的A*写的,可是居然会超时。我怎么觉得比bfs算法复杂度低呢?
# 读取输入数据
[M,N]= list(map(int,input().split()))
maxz = []
for x in range(M):
    maxz.append(list(input()))

# -------------------------------------------------
# M=5
# N=5
# maxz=[['0','2','1','1','1'],
#       ['0','1','a','0','A'],
#       ['0','1','0','0','3'],
#       ['0','1','0','0','1'],
#       ['0','1','1','1','1']]
# -------------------------------------------------
# 数据初始化

start0 = []
end0 = []

# 提取所有带字母的钥匙和门
dicta = []
dictb = []

for x in range(M):
    for y in range(N):
        if maxz[x][y] == '2':
            start0 = [x, y]
        elif maxz[x][y] == '3':
            end0 = [x, y]
        elif 96 < ord(maxz[x][y]) < 123&nbs***bsp;64 < ord(maxz[x][y]) < 91:
            dicta.append([maxz[x][y], x, y])

# 按钥匙字母排序
dicta.sort(key=lambda x: x[0])
lena = len(dicta)

# 转换成钥匙和门的组合
for x in range(lena // 2):
    dictb.append(dicta[(lena // 2) + x][1:3])
    dictb.append(dicta[x][1:3])

# ---------------------------------------------------------

# 计算 G,H,F,P值   G为当前点到起点的距离,H为当前点到终点的距离,F为G+H,P为来源点
def distance(Node_current7, yuandian, start8, end8):
    P = yuandian
    G = abs(Node_current7[0] - start8[0]) + abs(Node_current7[1] - start8[1])
    H = abs(Node_current7[0] - end8[0]) + abs(Node_current7[1] - end8[1])
    F = G + H
    return [F, P]

# 查找周围的临接点
def findNeighbors(nc, maxz9, Node_start7, Node_end7):
    open_list9 = []

    if nc[0] > 0:  # 取上面的点
        if maxz9[nc[0] - 1][nc[1]] != '0':
            open_list9.append([nc[0] - 1, nc[1], distance([nc[0] - 1, nc[1]], nc[0:2], Node_start7, Node_end7)])
    if nc[0] < M - 1:  # 取下面的点
        if maxz9[nc[0] + 1][nc[1]] != '0':
            open_list9.append([nc[0] + 1, nc[1], distance([nc[0] + 1, nc[1]], nc[0:2], Node_start7, Node_end7)])
    if nc[1] > 0:  # 取左面的点
        if maxz9[nc[0]][nc[1] - 1] != '0':
            open_list9.append([nc[0], nc[1] - 1, distance([nc[0], nc[1] - 1], nc[0:2], Node_start7, Node_end7)])
    if nc[1] < (N - 1):  # 取右面的点
        if maxz9[nc[0]][nc[1] + 1] != '0':
            open_list9.append([nc[0], nc[1] + 1, distance([nc[0], nc[1] + 1], nc[0:2], Node_start7, Node_end7)])
    return open_list9

# 从openlist找到F值最小
def findMinNode(openlist_temp):
    y1 = openlist_temp[0]
    for x1 in openlist_temp:
        if y1[2][0] > x1[2][0]:
            y1 = x1
    return y1

# A*搜索
def aStarSearch(Node_start, Node_end, maxz0):
    OpenList = []
    CloseList = []
    Node_current = []
    List_neighbors = []
    term_result = []

    #     把起点加入 open list
    OpenList.append([Node_start[0], Node_start[1], [0, [-1, -1]]])
    #     主循环,每一轮检查一个当前方格节点
    while len(OpenList) > 0:
        # 在OpenList中查找 F值最小的节点作为当前方格节点
        Node_current = findMinNode(OpenList)
        # 当前方格节点从open list中移除
        OpenList.remove(Node_current)
        # 当前方格节点进入 close list
        CloseList.append(Node_current)

        # 找到所有邻近节点
        List_neighbors = findNeighbors(Node_current, maxz0, Node_start, Node_end)
        for x in List_neighbors:
            if (x not in OpenList) & (x not in CloseList):
                # 邻近节点不在OpenList,CloseList中,标记父亲、G、H、F,并放入OpenList
                OpenList.append(x)

        # 如果终点在OpenList中,直接返回路径
        for x in OpenList:
            if Node_end == x[0:2]:  # 如果找到
                term_result.append(x[0:2])
                temp0 = x
                while Node_start != temp0[0:2]:
                    for z in CloseList:
                        if temp0[2][1] == z[0:2]:
                            temp0 = z
                            term_result.append(temp0[0:2])
                            break
                term_result.pop()
                # print(term_result[::-1])
                return len(term_result)

    # OpenList用尽,仍然找不到终点,说明终点不可到达,返回空
    return None


#逐个遍历各个位置,从起点 到第一个钥匙,然后再到第一个门,如果有其他钥匙,再循环,最后去出口。循环计算两点间的距离。
dictb.insert(0, start0)
dictb.append(end0)
sum0 = 0

for y in range(len(dictb) - 1):
    sum0 += aStarSearch(dictb[y], dictb[y + 1], maxz)

print(sum0)


发表于 2020-02-09 15:57:26 回复(0)
from queue import Queue
class node:
    def __init__(self, x, y, status, dis):
        self.x = x
        self.y = y
        self.status = status
        self.dis = dis
def MGXL():
    #移动增量
    dx = [-1, 1, 0, 0] #上下
    dy = [0, 0, -1, 1] #左右
    #队列
    q = Queue()
    #输入
    m, n = map(int, input().split())
    mp = []
    for i in range(m):
        mp.append(list(input()))
    #构建三维数组
    vis = [[[0 for i in range(1024)] for j in range(101)] for k in range(101)]
    #获取起点
    sx = 0
    sy = 0
    for i in range(m):
        for j in range(n):
            if mp[i][j] == '2':
                sx = i
                sy = j
                break
    vis[0][sx][sx] = 1
    q.put(node(sx, sy, 0, 0))
    while bool(1-q.empty()):
        p = q.get()
        if mp[p.x][p.y] == '3':
            print(p.dis)
            break
        for i in range(4):
            xx = p.x + dx[i]
            yy = p.y + dy[i]
            if xx < 0 or xx >= m or yy < 0 or yy >= n or mp[xx][yy] == '0' or vis[p.status][xx][yy]:
                continue
            if 'Z' >= mp[xx][yy] >= 'A':
                if p.status & (1 << ord(mp[xx][yy])-ord('A')):
                    vis[p.status][xx][yy] = 1
                    q.put(node(xx, yy, p.status, p.dis + 1))
            elif 'z' >= mp[xx][yy] >= 'a':
                vis[p.status | (1<<(ord(mp[xx][yy])-ord('a')))][xx][yy] = 1
                q.put(node(xx, yy, p.status | (1<<(ord(mp[xx][yy])-ord('a'))), p.dis + 1))
            else:
                vis[p.status][xx][yy] = 1
                q.put(node(xx, yy, p.status, p.dis+1))
if __name__ == '__main__':
    MGXL()
求助,一直说运行时间超时,只AC过了30%,Python大神帮忙看一下
发表于 2019-03-21 16:36:15 回复(0)
#DFS爆栈,BFS超时,求大佬指点一蛤😭😭😭 #
#
def migongwithkeys(A):
    class node(object):
        def __init__(self,x,y,k,step):
            self.x = x
            self.y = y
            self.k = k
            self.step = step
    

    d = [[-1,0],[0,1],[1,0],[0,-1]]
    def dfs(A,R,visited,h,l,step,key):
        if (not 0 <= h < R[0]) or not (0 <= l < R[1]) or A[h][l] == 0 or visited[h][l]:
            return
        elif A[h][l] == 3:
            res[0] = min(res[0],step)
            return
        elif str(A[h][l]).isupper() and (not A[h][l].lower() in key):
            return
        else:
            visited[h][l] = True
            if str(A[h][l]).islower():
                key.append(A[h][l])
                for i in range(R[0]):
                    for j in range(R[1]):
                        visited[i][j] = False

            for a,b in d:
                visited[h][l] = True
                dfs(A,R,visited,h+a,l+b,step+1,key)
                visited[h][l] = False
    
    def bfs(A,visited,R,h,l):
        Q = []
        Q.append(node(h,l,0,0))
        while len(Q) > 0:
            print('out')
            head = Q.pop(0)
            if A[head.x][head.y] == 3:
                return head.step
            for a,b in d:
                nx, ny = head.x + a, head.y + b
                if (not 0 <= nx < R[0]) or (not 0 <= ny < R[1]) or A[nx][ny] == 0:
                    continue
                key = head.k
                if str(A[nx][ny]).islower():
                    key = key | (1 << ord(A[nx][ny]) - ord('a'))
                if str(A[nx][ny]).isupper() and (key & (1 << ord(A[nx][ny]) - ord('A')) == 0):
                    continue
                if not visited[nx][ny][key]:
                    visited[nx][ny][key] == True
                    Q.append(node(nx,ny,key,head.step + 1))
                    print('in')
                
    
    
    res = [float('inf')]
    
    m,n = len(A),len(A[0])
    visited_d = [[False] * n for _ in range(m)]
    visited_b = [[[False] * 105 for _ in range(105)] for _ in range(1200)]
    
    R = [m,n]
    for i in range(m):
        for j in range(n):
            if A[i][j] == 2:
                h,l = i,j
                visited_b[h][l][0] = True
    #dfs(A,R,visited_d,h,l,0,[])
    ans = bfs(A,visited_b,R,h,l)
    return ans



编辑于 2019-03-07 11:48:28 回复(1)