题目描述:
又是晴朗的一天,牛牛的小伙伴们都跑来找牛牛去公园玩。但是牛牛想呆在家里看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)
欢迎指正哦。