广度优先搜索-鸣人和佐助
鸣人和佐助:佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢?
已知一张地图(以二维矩阵的形式表示)以及佐助和
鸣人的位置。地图上的每个位置都可以走到,只不过有些位置上有
大蛇丸的手下(#),需要先打败大蛇丸的手下才能到这些位置。
鸣人有一定数量的查克拉,每一个单位的查克拉可以打败一
个大蛇丸的手下。假设鸣人可以往上下左右四个方向移动,
每移动一个距离需要花费1个单位时间,打败大蛇丸的手下
不需要时间。如果鸣人查克拉消耗完了,则只可以走到没有
大蛇丸手下的位置,不可以再移动到有大蛇丸手下的位置。
佐助在此期间不移动,大蛇丸的手下也不移动。请问,鸣人
要追上佐助最少需要花费多少时间?
输入:输入的第一行包含三个整数:M,N,T。代表M行N列的地图和
鸣人初始的查克拉数量T。0 < M,N < 200,0 ≤ T < 10
后面是M行N列的地图,其中@代表鸣人,+代表佐助。*代表通路,#代表大蛇丸的手下。
输出:输出包含一个整数R,代表鸣人追上佐助最少需要花费的时间。
如果鸣人无法追上佐助,则输出-1。
样例输入1
4 4 1
#@##
**##
###+
****
样例输出1
6
样例输入2
4 4 2
#@##
**##
###+
****
样例输出2
4
一个经典的错误样例;
3 6 1
@#****
*#*###
***##+
正确答案应该是11;
但是如果利用二维标记答案是-1;因为二维标记是bfs找最短路,
当(1,1)——>(2,1)——>(3,1)——>(3,2)——>(3,3)——>(2,3)——>(1,3),
当这样找到(1,3)时,(1,3)早已经被(1,1)——>(1,2)——>(1,3)
走过并标记了,所以这条不需要查克拉的路就走不下去了,输出-1;
用三维数组就可以避免这种情况;比如刚才走到(1,3)这个点,区分有0、1查克拉的情况
visited[1][3][0] = 1,走到该点(1,3),用了1个,目前查克拉数量是0
visited[1][3][1] = 1,走到该点(1,3),没有用过1查克拉,目前查克拉数量是1,
这样就可以描述通过不同路径走到该点,拥有查克拉的数量的三维数组来描述状态,
都是到达(1,3)这个点,但是查克拉的数量不一致,所以就是新的一种状态,这样就不与
之前的路产生冲突了。
思路:这道题的状态是什么?是又鸣人的所在位置以及鸣人所剩查克拉决定的,(i,j,n),
初始状态是(i0,j0,N),终止状态是(i,i,n),达到佐助位置即可。
因为用广搜,所以到达即是最短。用广搜的话就要加入查克拉的消耗情况,
所以是三维的visit数组。
这题与以往不一样的地方在于该点走过后,还是可以再访问的,因为多了一个查克拉的值。
https://blog.csdn.net/WaveBridge/article/details/74993874
python代码:
1 import queue 2 3 # 地图 4 maps = [] 5 # 分别代表鸣人和佐助的位置 6 r1, c1, r2, c2 = 0, 0, 0, 0 7 # 访问标记 8 visited = [] 9 # 四个方向数组 10 direction = [[1, 0], [-1, 0], [0, 1], [0, -1]] 11 12 13 class Node: 14 # 所在位置 15 r = 0 16 c = 0 17 # 查克拉剩余 18 t = 0 19 # 所在层数,路径长度 20 level = 0 21 22 def __init__(self, rr, cc, tt, level1): 23 self.r = rr 24 self.c = cc 25 self.t = tt 26 self.level = level1 27 28 29 # 获取鸣人和佐助的r,c 30 def getTwoDimensionListIndex(list_map, value): 31 r, c = 0, 0 32 for i in range(len(list_map)): 33 for j in range(len(list_map[i])): 34 if list_map[i][j] == value: 35 r = i 36 c = j 37 break 38 return r, c 39 40 41 def bfs(r, c, k): 42 global maps, r1, c1, r2, c2, visited 43 new_node = Node(r1, c1, k, 0) 44 q = queue.Queue() 45 q.put(new_node) 46 while not q.empty(): 47 temp = q.get() 48 # 找到佐助 49 if temp.r == r2 and temp.c == c2: 50 cost_time = temp.level 51 return cost_time 52 # 把当前节点四个方向的节点入队 53 for i in range(4): 54 temp2 = Node(0, 0, 0, 0) 55 temp2.r = temp.r + direction[i][0] 56 temp2.c = temp.c + direction[i][1] 57 # 保证访问的点不越界 58 if 0 <= temp2.r < r and 0 <= temp2.c < c: 59 # 若为"#"并且查克拉够 并且没访问过 可访问 60 if maps[temp2.r][temp2.c] == "#" and temp.t >= 1 and visited[temp2.r][temp2.c][temp.t-1] == 0: 61 temp2.t = temp.t - 1 62 temp2.level = temp.level + 1 63 q.put(temp2) 64 visited[temp2.r][temp2.c][temp2.t] = 1 65 # 不是# 并且未访问过 66 elif maps[temp2.r][temp2.c] != "#" and visited[temp2.r][temp2.c][temp.t] == 0: 67 temp2.t = temp.t 68 temp2.level = temp.level + 1 69 q.put(temp2) 70 visited[temp2.r][temp2.c][temp2.t] = 1 71 return 0 72 73 74 def main(): 75 global maps, r1, c1, r2, c2, visited 76 # k-查克拉的数量 77 r, c, k = map(int, input().split()) 78 79 for i in range(r): 80 temp = list(input()) 81 maps.append(temp) 82 # [['#', '@', '#', '#'],['*', '*', '#', '#'], 83 # ['#', '#', '#', '+'],['*', '*', '*', '*']] 84 # 查找鸣人和佐助的位置 85 r1, c1 = getTwoDimensionListIndex(maps, "@") 86 r2, c2 = getTwoDimensionListIndex(maps, "+") 87 visited = [[[0 for i in range(k+1)] for j in range(c)] for e in range(r)] 88 """ 89 三维的visited列表 90 [ 91 [[0, 0], [0, 0], [0, 0], [0, 0]], 92 [[0, 0], [0, 0], [0, 0], [0, 0]], 93 [[0, 0], [0, 0], [0, 0], [0, 0]], 94 [[0, 0], [0, 0], [0, 0], [0, 0]] 95 ] 96 """ 97 # 从这里出发,置状态为1,表示访问过 98 visited[r1][c1][k] = 1 99 rtn = bfs(r, c, k) 100 if rtn == 0: 101 print("-1") 102 else: 103 print("鸣人追上佐助最少需要花费的时间为:%d" % rtn) 104 105 106 if __name__ == '__main__': 107 main()