19930: 寻宝
bfs, http://cs101.openjudge.cn/practice/19930
Billy获得了一张藏宝图,图上标记了普通点(0),藏宝点(1)和陷阱(2)。按照藏宝图,Billy只能上下左右移动,每次移动一格,且途中不能经过陷阱。现在Billy从藏宝图的左上角出发,请问他是否能到达藏宝点?如果能,所需最短步数为多少?
输入
第一行为两个整数m,n,分别表示藏宝图的行数和列数。(m<=50,n<=50) 此后m行,每行n个整数(0,1,2),表示藏宝图的内容。
输出
如果不能到达,输出‘NO’。 如果能到达,输出所需的最短步数(一个整数)。
样例输入
样例输入1:
3 4
0 0 2 0
0 2 1 0
0 0 0 0
样例输出1:
5样例输出
样例输入2:
2 2
0 2
2 1
样例输出2:
NO提示
每张藏宝图有且仅有一个藏宝点。 输入保证左上角(起点)不是陷阱。
来源:by cs101-2009 邵天泽
其实所有求最短、最长的问题都能用heapq实现,在图搜索中搭配bfs尤其好用。
python
#23 工学院 苏王捷
import heapq
def bfs(x,y):
d=[[-1,0],[1,0],[0,1],[0,-1]]
queue=[]
heapq.heappush(queue,[0,x,y])
check=set()
check.add((x,y))
while queue:
step,x,y=map(int,heapq.heappop(queue))
if martix[x][y]==1:
return step
for i in range(4):
dx,dy=x+d[i][0],y+d[i][1]
if martix[dx][dy]!=2 and (dx,dy) not in check:
heapq.heappush(queue,[step+1,dx,dy])
check.add((dx,dy))
return "NO"
m,n=map(int,input().split())
martix=[[2]*(n+2)]+[[2]+list(map(int,input().split()))+[2] for i in range(m)]+[[2]*(n+2)]
print(bfs(1,1))找最短路径,是bfs,借助队列queue实现,head和tail分别指向队列的头和尾。
python
q = []
step = [[0, 1], [1, 0], [-1, 0], [0, -1]]
vis = [[0] * 52 for _ in range(52)]
g = []
m, n = map(int, input().split())
for i in range(m):
g.append([int(x) for x in input().split()])
def check(x, y):
if (x < 0 or y < 0 or x >= m or y >= n):
return False
if (vis[x][y] or g[x][y] == 2):
return False
return True
q.append((0, 0))
head = 0
tail = 1
level = 0
while (head < tail):
# i = head
# j = tail
for k in range(head, tail):
x, y = q[head]
head += 1
if (g[x][y] == 1):
print(level)
exit(0)
for z in range(4):
newx = x + step[z][0]
newy = y + step[z][1]
if (check(newx, newy)):
vis[newx][newy] = 1
q.append((newx, newy))
tail += 1
level += 1
print('NO')