题目描述:
又是晴朗的一天,牛牛的小伙伴们都跑来找牛牛去公园玩。但是牛牛想呆在家里看E3展,不想出去逛公园,可是牛牛又不想鸽掉他的小伙伴们,于是找来了公园的地图,发现公园是由一个边长为n的正方形构成的,公园一共有m个入口,但出口只有一个。公园内有一些湖和建筑,牛牛和他的小伙伴们肯定不能从他们中间穿过,所以只能绕行。牛牛想知道他需要走的最短距离并输出这个最短距离。
第一行输入一个数字n(1≤n≤1000)表示公园的边长接下来会给你一个n*n的公园地图,其中 . 表示公园里的道路,@ 表示公园的入口,* 表示公园的出口,# 表示公园内的湖和建筑。牛牛和他的小伙伴们每次只能上下左右移动一格位置。输入保证公园入口个数m(1≤m≤10000)且所有的入口都能和出口相连。
输入10
mat = [['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'], ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'], ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'], ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'], ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'], ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'], ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'], ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'], ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']]输出
16
问题分析:广度优先搜索(Breadth First Search,BFS)
采用广度优先搜索的思想,首先每找到一个入口,进行一次广度优先搜索,用队列实现,但是每次出队的时候,并不是真正的出队,只让队头指针向后移动一次,这是为了,在找到出口的时候回溯到起点,以便求出最短路径,所以在入队的时候,要记录前一个结点的位置用于回溯。
Python3实现:
# 广度优先搜索,队列实现 # @Time :2018/6/20 # @Author :LiuYinxing def findpath(mat, n, row, col): path = [[1]*n for _ in range(n)] path[row][col] = 0 # 初始化队头 pre = -1 qlist = [[row, col, pre]] while qlist: pre += 1 # 出队 i, j = qlist[pre][0], qlist[pre][1] if -1 < i-1: # 上 if path[i-1][j] == 1 and mat[i-1][j] == '.': qlist.append([i-1, j, pre]) # 入队 path[i-1][j] = 0 # 标记一下,已经走过了 elif path[i-1][j] == 1 and mat[i-1][j] == '*': # 出口 qlist.append([i - 1, j, pre]) # 入队 break if j+1 < n: # 右 if path[i][j+1] == 1 and mat[i][j+1] == '.': qlist.append([i, j+1, pre]) path[i][j+1] = 0 elif path[i][j+1] == 1 and mat[i][j+1] == '*': qlist.append([i, j+1, pre]) break if i+1 < n: # 下 if path[i+1][j] == 1 and mat[i+1][j] == '.': qlist.append([i+1, j, pre]) path[i+1][j] = 0 elif path[i+1][j] == 1 and mat[i+1][j] == '*': qlist.append([i + 1, j, pre]) break if j-1 > -1: # 左 if path[i][j-1] == 1 and mat[i][j-1] == '.': qlist.append([i, j-1, pre]) path[i][j-1] = 0 elif path[i][j-1] == 1 and mat[i][j-1] == '*': qlist.append([i, j-1, pre]) break fpath = [qlist[-1]] # 回溯计算最短路径 while pre != -1: fpath.append(qlist[pre]) pre = qlist[pre][2] print(len(fpath)-1, fpath[::-1]) return len(fpath)-1 def minpath(mat, n): # 获取所有入口的最短路径,并且选择小的一个 minpath = float('inf') for i in range(n): for j in range(n): if mat[i][j] == '@': minpath = min(findpath(mat, n, i, j), minpath) print('最短路径长度为:', minpath) if __name__ == '__main__': n, m = 10, 4 mat = [ ['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'], ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'], ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'], ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'], ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'], ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'], ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'], ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'], ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']] minpath(mat, n)
Python3(简化代码):
# 广度优先搜索,队列实现 # @Time :2018/6/20 # @Author :LiuYinxing def findpath(mat, n, row, col): path = [[1]*n for _ in range(n)] path[row][col] = 0 # 初始化队头 pre = -1 qlist = [[row, col, pre]] while qlist: pre += 1 # 出队 i, j = qlist[pre][0], qlist[pre][1] if checkplace(mat, path, qlist, n, pre, i-1, j): break # 上 if checkplace(mat, path, qlist, n, pre, i, j+1): break # 右 if checkplace(mat, path, qlist, n, pre, i+1, j): break # 下 if checkplace(mat, path, qlist, n, pre, i, j-1): break # 左 fpath = [qlist[-1]] # 回溯计算最短路径 while pre != -1: fpath.append(qlist[pre]) pre = qlist[pre][2] print(len(fpath)-1, fpath[::-1]) return len(fpath)-1 def checkplace(mat, path, qlist, n, pre, row, col): # 判断新节点是否是出口 if -1 < row < n and -1 < col < n and path[row][col] == 1: if mat[row][col] == '.': qlist.append([row, col, pre]) # 入队 path[row][col] = 0 elif mat[row][col] == '*': # 出口 qlist.append([row, col, pre]) # 入队 return 1 def minpath(mat, n): # 获取所有入口的最短路径,并且选择小的一个 minpath = float('inf') for i in range(n): for j in range(n): if mat[i][j] == '@': minpath = min(findpath(mat, n, i, j), minpath) print('最短路径长度为:', minpath) if __name__ == '__main__': n, m = 10, 4 mat = [['.', '@', '.', '.', '.', '.', '#', '#', '@', '.'], ['.', '.', '.', '.', '.', '.', '#', '.', '.', '.'], ['.', '.', '.', '@', '.', '.', '#', '.', '.', '.'], ['#', '#', '#', '.', '.', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '#', '#', '.', '.', '#', '.'], ['.', '.', '.', '#', '#', '#', '#', '.', '.', '.'], ['@', '.', '.', '.', '#', '#', '.', '.', '.', '.'], ['#', '#', '#', '#', '#', '.', '.', '.', '.', '.'], ['.', '.', '#', '#', '*', '#', '#', '#', '#', '.'], ['#', '.', '.', '.', '.', '.', '.', '.', '.', '.']] minpath(mat, n)欢迎指正哦。