1. 程式人生 > 其它 >混亂的地鐵(廣度優先搜尋)

混亂的地鐵(廣度優先搜尋)

題目描述:

在某一個城市中地鐵網極度混亂。一條地鐵線路上有 n 個地鐵站,分別編號為 1 到 n。地鐵線路上的每一個站都會停靠地鐵,每一個地鐵站上都有一個數字 m,代表從此站出發乘客必須乘坐的站數。

每個地鐵站都有通往兩個方向的地鐵。因此既可以向編號大的方向前進 m 站,也可以向編號小的方向前進 m 站。但如果前進後超出了地鐵站的範圍,則該地鐵不可被乘坐。例如編號為 1 的地鐵上的數字為 3,那麼在該地鐵站上車,可以向正方向坐車到 4 號地鐵站。但不能反方向坐車到 -2 號地鐵站,因為 -2 號地鐵站不存在。現在乘客從 A 號地鐵站出發,想要到達 B 號地鐵站,求他能否到達,最少要搭乘多少次地鐵?

題目分析:

在分析這個問題前先舉一個具體的例子。如下圖 所示,如果一共有 5 個地鐵站,其編號依次為 1,2,3,4,5。而每個地鐵站的數字分別為 2,4,1,2,3。現在我們來分析乘客從 1 號地鐵站上車,想要到達 2 號地鐵站的情況。

如果乘客從 1 號地鐵站出發,則他有兩個選擇,向正方向坐車,或向反方向坐車。1 號車站的數字為 2,因此可以到達 3 號地鐵站和 -1 號地鐵站。又因為 -1 號地鐵站並不存在,所以從 1 號地鐵站出發只能到達 3 號地鐵站。綜上我們可以得出結論:從 1 號地鐵站出發,到達 3 號地鐵站最少要坐一趟地鐵,如下圖所示。

此時到達 3 號地鐵站。3 號地鐵站的數字為 1,因此可以向正方向坐 1 站車到達 4 號地鐵站,也可以向反方向坐 1 站車直接到達目的地 2 號地鐵站。同樣我們也可以得出結論:從 1 號地鐵站出發,到達 2 號地鐵站和 4 號地鐵站至少需要坐兩趟地鐵,如圖 下所示。

此時我們已經遍歷出結果:從 1 號地鐵站出發到達 2 號地鐵站至少要乘坐兩次地鐵。如果我們的迴圈跳出條件設立的是到達目的地或者佇列為空,那麼遍歷已經結束。但是如果我們的迴圈跳出條件只有佇列為空,那麼我們還需進一步遍歷,因為此時佇列中仍有兩個元素:4 號地鐵站和 2 號地鐵站。

值得注意的是,當我們從 4 號地鐵站出發時,如果向正方向乘坐 2 站地鐵(4 號地鐵站上的數字為 2),將超出地鐵站範圍,因此無法向正方向乘坐地鐵。如果向反方向乘坐 2 站地鐵,將會到達目的地 2 號地鐵站。當我們按照從 1 號地鐵站出發,到達 3 號地鐵站,再到達 4 號地鐵站,最終到達 2 號地鐵站的話需要乘坐 3 趟地鐵,沒有上一種地鐵乘坐方案便利,應當淘汰這種方案,如下圖 所示。

但如果仔細思考使用佇列資料結構的廣度優先搜尋演算法,不難推匯出最優的方案一定比次優的方案先進入佇列中。因為廣度優先搜尋演算法具有層次性,每一次遍歷距離最近或距離相同的目標。如果距離近是問題答案最重要的考察因素,則廣度優先搜尋演算法會自動地優先搜尋距離較近的目標,最快地找到問題的答案。

所以,我們只需建立一個數組或列表來記錄是否已經遍歷過一個目標,防止重複遍歷同一目標導致無限迴圈即可,不需再擔心最優的答案可能出現在重複的遍歷過程中。

依舊使用廣度優先搜尋演算法的模板,我們在一個 while 迴圈內對佇列結構進行遍歷操作,迴圈的跳出條件依舊為佇列為空。

程式碼:

from queue import Queue

move=[2,4,1,2,3]    #move列表裡儲存每一個地鐵站的數字
q=Queue()
start,end,num=map(int,input().split())    #出發點、目的地、總共的地鐵站數量
station=[-1 for i in range(num+1)]     #列表儲存從出發點到對應地鐵站需乘坐地鐵的趟數,-1代表無法到達   
q.put(start)
station[start]=0        #出發點到自身地鐵站時不用乘坐任何地鐵,賦值為0

while not q.empty():
    cur=q.get()      #取出佇列第一項,並將其移出佇列
    left=cur-move[cur-1]    #計算出向反方向乘坐會到達哪個地鐵站
    right=cur+move[cur-1]    #計算出向正方向乘坐會到達哪個地鐵站
    if left>=1 and station[left]==-1:
        q.put(left)
        station[left]=station[cur]+1
    if right<=num and station[right]==-1:
        q.put(right)
        station[right]=station[cur]+1

if __name__=='__main__':
    print(station[end])        #輸出答案