A 搜尋求最短路

2021-06-16 07:07:55 字數 1986 閱讀 9949

以下文章**

原來這就是傳說中的a*.第一次寫的a*,多多感謝alpc55推薦的這道好題。先說說原先讀到這到題目的想法,以前也聽講過k短路,我還以為就是多做幾次dijkstra,或是在dijkstra演算法選邊的時候控制一些條件。聽alpc55說是用a*啟發式搜尋,直接使用廣度優先搜尋會暴空間。當時聽著也不怎麼理解,就是把這些話記下來了。回來搞了兩天,也翻了些資料,終於把這個演算法弄出來了。

先說說啟發式搜尋吧。通常在解決問題的時候,我們需要用到搜尋演算法,由已知狀態推出新的狀態,然後檢驗新的狀態是不是就是我們要求的最優解。檢驗完所有的狀態實際上就相當於遍歷了一張隱式圖。遺憾的是,所有的狀態組成的狀態空間往往是成指數級別增長的,也就造成了遍歷需要用到指數級別的時間,因此,純粹的暴力搜尋,時空效率都比較低。當然,我們在生活中遇到了類似於搜尋的問題,我們並不會盲目地去搜尋每一種狀態,我們會通過我們的思維,選擇一條最接近於目標的路徑或者是近似於最短的路徑去完成搜尋任務。當我們想要計算機去完成這樣一項搜尋任務的時候,就得讓計算機像人一樣能夠區分盡量短的路徑,以便高效地找到最優解。這時可以把計算機看作是一種智慧型體(agent)可以實現由初始狀態向目標狀態的轉移。

有一種貪心策略,即每一步轉移都由計算機選擇當前的最優解生成新的狀態,一直到達目標狀態為止。這樣做的時間效率雖然較高,但是貪心的策略只是用到了區域性的最優解,並不能保證最後到達目標狀態得到的是全域性最優解。在能保證全域性最優解的範圍內,貪心演算法還是很有用的。比如說我們熟知的dijkstra演算法求單源最短路。每次選擇距離源節點最短距離的待擴充套件節點進行擴充套件,最後就能生成源節點到所有節點的最短路徑。下面會講到dijkstra的擴充套件,當理解了這個演算法之後,我想,你會對dijkstra有更深入的理解。

這就是a*演算法。定義初始狀態s,目標狀態t,g(s)是由初始狀態轉移到當前狀態s所經過的路徑長度,h*(s)是當前狀態s距離目標狀態t的實際長度,但是一般情況下我們是不知道h*(s)的值的,所以還要定義乙個估價函式h(s),是對h*(s)函式值的下界的估計,也就是有h(s)<=h*(s),這樣需要乙個條件,使得由s1生成的每狀態s2,都有h(s1)<=h(s2),這是乙個相容的估價函式。再定義f(s)=g(s)+h(s)為啟發函式,因為h(s)是單調遞增的,所以f(s)也是單調遞增的。這樣f(s)就估計出了由初始狀態的總體代價。a*演算法就通過構造這樣乙個啟發函式,將所有的待擴充套件狀態加入到佇列裡,每次從佇列裡選擇f(s)值最小的狀態進行擴充套件。由於啟發函式的作用,使得計算機在進行狀態轉移的時候盡量避開了不可能產生最優解的分支,而選擇相對較接近最優解的路徑進行搜尋,提高了搜尋效率。

講到這裡,可能已經對a*演算法的概念有點眉目了。下面我再來做乙個比較,就用上面講到的dijkstra的例子。dijkstra演算法說的是每次選擇距離源點最短距離的點進行擴充套件。當然可以看做事先將源點到所有節點距離的值儲存在乙個優先佇列裡,每次從優先佇列裡出隊最短距離的點擴充套件,每個點的擴充套件涉及到要更新佇列裡所有待擴充套件節點的距離值,每個節點只能進隊一次,就需要有乙個表來記錄每個節點的入隊次數(就是演算法中用到的標記陣列)。將dijkstra求最短路的方法擴充套件,這道題目要求的是兩點間第k短路。模擬於dijkstra演算法可以首先確定下面幾個搜尋策略:

1、用優先佇列儲存節點進行搜尋。

2、放開每個節點的入隊次數,求k短路,每個節點可以入隊k次。

首先看第乙個策略,在a*演算法中用優先佇列就是要用到啟發函式f(s)確定狀態在優先佇列裡面的優先順序。其實dijkstra用到的優先佇列實際上就是估價函式值為0,啟發函式f(s)=g(s),即是選取到源點距離最近的點進行擴充套件。因為h(s)=0滿足了估價函式相容這個條件。這題求k短路就不能單純的使用h(s)=0這個估價函式。解決這道題的時候選取h(x)=dt(x), dt(x)是x節點到目標節點的最短距離。最短距離可以開始由dijkstra直接求得。

再看第二個策略,控制每個節點的入隊(或出隊)次數為k次,可以找到第k短路徑。可能這樣想有點主觀的套用,那麼我就先來證明這樣乙個結論:

如果x是s到t的第k短路徑上的乙個節點,那麼由這條路徑s到x是s到x的第m短路徑,則不可能有m>k。用反證法很容易得出:如果這條路徑是s到x的第m短路徑,如果m>k,那麼經過x到t的路徑就有m-1條比當前路徑要短,不符合當前路徑是s到t的第k短路徑。

利用廣度優先搜尋求最短路徑

注 下面是以無權的圖為基礎的 廣度優先搜尋 輸入 輸入n個頂點,m條邊,起點的編號 跟著再輸入邊x,y 輸出 該起點到達各個頂點最少經過幾條邊 按編號從小打大輸出,包括自己哦 樣例 輸入 5 5 2 1 22 3 2 43 4 3 5 輸出 1 0112 我一開始就是覺得用廣度優先搜尋,結果在廣度優...

演算法 深度優先搜尋,求迷宮內兩點最短路徑問題

問題描述 在乙個迷宮裡,規定 0 代表可以通過,1 代表有障礙物。尋求從初始值 row0,col0 到末值 row,col 最短路徑是多少 例 0 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 在兩點之間一定能到達的前提下。要不然就沒意思了。includeusing n...

搜尋 最短路 找朋友

找朋友 找朋友 已知一組人名對,他們互為朋友關係,輸入乙個人名對,找到兩個人認識的最短關係路徑 例如 輸入 輸出 mike,lucy,sean 注意 1.兩個人可能無法建立朋友關聯。2.如果同時存在兩條最短路徑,只要任意輸出一組。1 首先flody處理圖中任意兩點的距離。2 然後通過 dis a b...