廣度優先搜尋-鳴人和佐助
阿新 • • 發佈:2020-07-22
鳴人和佐助:佐助被大蛇丸誘騙走了,鳴人在多少時間內能追上他呢?
已知一張地圖(以二維矩陣的形式表示)以及佐助和
鳴人的位置。地圖上的每個位置都可以走到,只不過有些位置上有
大蛇丸的手下(#),需要先打敗大蛇丸的手下才能到這些位置。
鳴人有一定數量的查克拉,每一個單位的查克拉可以打敗一
個大蛇丸的手下。假設鳴人可以往上下左右四個方向移動,
每移動一個距離需要花費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 61
@#****
*#*###
***##+
正確答案應該是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()