艱難的旅行(廣度優先搜尋演算法)
阿新 • • 發佈:2021-07-15
題目描述:
現已知一個大小為 N · M 的地圖,地圖中只有可能出現兩個數字:0 或 1,規定如果位於數字為 0 的格子上,則下一步只能往相鄰四個格子中數字為 1 的格子走,如果位於數字為 1 的格子上,則下一步只能往相鄰四個格子中數字為 0 的格子走。如果給定起點格子,則可以向上下左右四個方向移動,且同一個格子不能重複走,求能在地圖中到達多少格子?
如下圖所示,假設地圖為一個方格圖,且給定的起點為左上角灰色的方格。
如左圖所示,從左上角的格子出發,可以從 1,到達右邊與下方的 0,再到達右邊與下方的 1,從而到達地圖上的所有方格。因此,圖 1 所示的地圖可以求解出的答案應為 25,即可以到達圖上的所有方格。而對於右圖而言,仍從左上角灰色的格子出發,我們會發現其右邊和下方的方格均為 1,因此無法移動到任何其他方格中,求解出能到達的格子數為 1。
題目分析:
分析完上面兩個基礎例子,就會自然地想到廣度優先搜尋演算法或許能解決這個問題。廣度優先搜尋演算法的核心思想是佇列,我們先建立一個佇列結構。因為廣度優先搜尋演算法優先搜尋離起始點最近的點,所以可以通過判斷現在位於的方格的上下左右四個方格是否能到達來構建佇列。我們可以用list來模擬佇列,append()入隊,pop(0)出隊。
如果一個格子可以到達,則加入佇列的末尾,如果不能到達則跳過。以這種方式來更新佇列,可以保證每一種移動方案均能被考慮到。而為了不重複遍歷相同的路徑,我們需用一個列表來儲存一個格子是否被加入佇列過,防止浪費計算資源。
程式碼:
def jndlx(grid,start,end): #grid:二維地圖,start,end:旅行起點位置
row =len(grid)
col=len(grid[0])
q = [] #用來模擬佇列,先進先出
q.append((start,end)) #加入起始點
arrived=[[False for _ in range(col)] for _ in range(row)] #標記有無訪問過,防止重複訪問
ans=0
def bfs(i,j): #廣度優先搜尋,判斷當前點的上下左右是否滿足條件,滿足的加入佇列
if 0<=i-1<row and 0<=j<col and not arrived[i-1][j] and grid[i][j]!=grid[i-1][j]:
arrived[i-1][j]=True
q.append((i-1,j))
if 0 <= i+1 < row and 0 <= j < col and not arrived[i+1][j] and grid[i][j] != grid[i + 1][j]:
arrived[i+1][j]=True
q.append((i + 1, j))
if 0<=i<row and 0<=j-1<col and not arrived[i][j-1] and grid[i][j]!=grid[i][j-1]:
arrived[i][j-1]=True
q.append((i,j-1))
if 0<=i<row and 0<=j+1<col and not arrived[i][j+1] and grid[i][j]!=grid[i][j+1]:
arrived[i][j+1]=True
q.append((i,j+1))
while q: #起點開始出隊,判斷該點的上下左右,滿足條件入隊,標記已訪問,迴圈直至佇列為空。
ans+=1
i,j=q.pop(0)
arrived[i][j]=True
bfs(i,j)
return ans
grid1=[[1,0,1,0,1],
[0,1,0,1,0],
[1,0,1,0,1],
[0,1,0,1,0],
[1,0,1,0,1]
]
grid2=[[1,0,0,1,0],
[1,1,0,1,0],
[0,0,0,1,0],
[1,1,1,1,0],
[0,0,0,0,0]]
grid3=[[1,1,0,1,0],
[1,0,0,1,0],
[0,0,0,1,0],
[1,1,1,1,0],
[0,0,0,0,0]]
print(jndlx(grid1,0,0))
print(jndlx(grid2,0,0))
print(jndlx(grid3,0,0))
/home/w/suanfa/venv/bin/python /home/w/suanfa/jndlx.py
25
9
1