1. 程式人生 > 實用技巧 >廣度優先搜尋-鳴人和佐助

廣度優先搜尋-鳴人和佐助

鳴人和佐助:佐助被大蛇丸誘騙走了,鳴人在多少時間內能追上他呢?
已知一張地圖(以二維矩陣的形式表示)以及佐助和
鳴人的位置。地圖上的每個位置都可以走到,只不過有些位置上有
大蛇丸的手下(#),需要先打敗大蛇丸的手下才能到這些位置。

鳴人有一定數量的查克拉,每一個單位的查克拉可以打敗一
個大蛇丸的手下。假設鳴人可以往上下左右四個方向移動,
每移動一個距離需要花費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()