viterbi演算法 利用動態規劃尋找最短路徑

2021-08-14 04:41:18 字數 2688 閱讀 1903

動態規劃是運籌學的乙個分支,是求解決策過程最優化的數學方法,通常情況下應用於最優化問題,這類問題一般有很多個可行的解,每個解有乙個值,而我們希望從中找到最優的答案。

在電腦科學領域,應用動態規劃的思想解決的最基本的乙個問題就是:尋找有向無環圖(籬笆網路)當中兩個點之間的最短路徑(實際應用於地圖導航、語音識別、分詞、機器翻譯等等)。

下面舉乙個比較簡單的例子做說明:求s到e的最短路徑。如下圖(各點之間距離不相同):

我們知道,要找到s到e之間最短路徑,最容易想到的方法就是窮舉法。也就是把所有可能的路徑都例舉出來。從s走向a層共有4種走法,從a層走向b層又有4種走法,從b層走向c層又有4種走法,然後c層走向e點只有一種選擇。所以最終我們窮舉出了4x4x4=64種可能。顯然,這種方法必定可行。但在實際的應用當中,對於數量極其龐大的結點數和邊數的圖,其計算複雜度也將會變得非常大,而計算效率也會隨之降低。

因此,這裡選擇使用一種基於動態規劃的方式來尋找最佳路徑。所謂動態規劃。其核心就是「動態」的概念,把大的問題細分為多個小的問題,基於每一步的結果再去尋找下一步的策略,通過每一步走過之後的區域性最優去尋找全域性最優。這樣解釋比較抽象,下面直接用回剛剛的例子說明。如下圖:

首先,我們假設s到e之間存在一條最短路徑(紅色),且這條路徑經過c2點,那麼我們便一定能夠確定從s到c2的64條(4x4x4=64)子路徑當中,該子路徑一定最短。(證明:反證法。如果s到c2之間存在一條更短的子路徑,那麼便可以用它來代替原先的路徑,而原先的路徑顯然就不是最短了,這與原假設自相矛盾)。

同理,我們也可以得出從s到b2點為兩點間最短子路徑的結論。這時候,真相便慢慢浮出水面:既然如此,我們計算從s點出發到點c2的最短路徑,是不是只要考慮從s出發到b層所有節點的最短路徑就可以了?答案是肯定的!因為,從s到e的「全域性最短」路徑必定經過在這些「區域性最短」子路徑。沒錯!這就是上面提及到的通過區域性最優的最優去尋找全域性最優,問題的規模被不斷縮小!

接下來,要揭曉答案了!繼續看下圖:

回顧之前的分析:我們計算從s起到c2點的最短路徑時候只需要考慮從s出發到b層所有節點的最短路徑,b層也如是。對b2來說,一共有4條路線可以到達,分別是a1→b2,a2→b2,a3→b2,a4→b2。我們需要做的就是把a2→b2這條最短路線保留,而其他3條刪除掉(因為根據以上的分析,它們不可能構成全程的最短路線)。ok,來到這裡,我們會發現乙個小「漏洞」,這段s→a2→b2→c2→e的路線只是我一廂情願的假設,最短路徑不一定是經過以上這些點。所以,我們要把每層的每個節點都考慮進來。

以下是具體的做法:step1:從點s出發。對於第一層的3個節點,算出它們的距離d(s,a1),d(s,a2),d(s,a3),d(s,a4),因為只有一步,所以這些距離都是s到它們各自的最短距離。

step2:對於b層的所有節點(b1,b2,b3,b4),要計算出s到它們的最短距離。我們知道,對於特定的節點b2,從s到它的路徑可以經過a層的任何乙個節點(a1,a2,a3,a4)。對應的路徑長就是d(s,b2)=d(s,ai)+d(ai,b2)(其中i=1,2,3,4)。由於a層有4個節點(即i有4個取值),我們要一一計算,然後找到最小值。這樣,對於b層的每個節點,都需要進行4次運算,而b層有4個節點,所以共有4x4=16次運算。

step3:這一步是該演算法的核心。我們從step2計算得出的結果只保留4個最短路徑值(每個節點保留乙個)。那麼,若從b層走向c層來說,該步驟的基數已經不再是4x4,而是變成了4!也就是說,從b層到c層的最短路徑只需要基於b層得出的4個結果來計算。這種方法一直持續到最後乙個狀態,每一步計算的複雜度為相鄰兩層的計算複雜度為4x4乘積的正比!再通俗點說,連線這兩兩相鄰層的計算符合變成了「+」號,取代了原先的「x」號。用這種方法,只需進行4x4x2=32次計算!

其實上述的演算法就是著名的維特比演算法,事實上非常簡單!

若假設整個網格的寬度為d,網格長度為n,那麼若使用窮舉法整個最短路徑的演算法複雜度為o(dn),而使用這種演算法的計算複雜度為o(nd2)。試想一下,若d與n都非常大,使用維特比演算法的效率將會提高幾個數量級!

**實現(c語言版):

同樣是實現從s到e的最短路徑。不過這次把剛剛的情況簡化了一下,原理是相同的。

#include#include#define x 9999

#define max 9999

int data[10][10];

int dist[10];//記錄最短路徑為多少

int path[10];//記錄最短路徑

int kmin(int,int);

void fpath(int a[10]);

int froute(int a[10]);

void main()

, ,,,

,,,,

,};

/*for (i=0;i<10;i++)

*/fpath(a);

printf("最短路徑大小為: %d\n",dist[9]);

m=froute(a);

for(i=m-1;i>=0;i--)

printf("最短路徑經過: %d\n",path[i]);

}void fpath(int a[10])}}

} return k;

}

js演算法利用

用for迴圈實現10的階乘1 function jc1 num else11 12 console.log for迴圈實現10的階乘 13 console.log str sum 14 15jc1 10 返回結果for迴圈實現10的階乘 10 10 9 8 7 6 5 4 3 2 1 3628800...

演算法 動態規劃

動態規劃 把多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解 演算法例子 1.鋼條切割 serling 公司購買長鋼條,將其切割為短鋼條,切割工序假設沒有成本支出,公司管理層希望確定最佳的切割方案。假設serling公司 一段長度為i英吋的鋼條的 為pi。鋼條的長度為整英吋,下表給出...

演算法 動態規劃

1 問題具有最優子結構性質。如果問題的最優解所包含的子問題的解也是最優的,我們就稱該問題具有最優子結構性質。比如說在揹包問題中,最高總價值 max 選擇不放該物品時達到的總價值,決定放該物品時揹包剩餘容量能達到的最大價值 該物品價值 顯然,最高總價值的解一定包含 選擇不放該物品時達到的總價值 和 決...