演算法設計與分析——動態規劃(一)矩陣連乘
動態規劃——Dynamic programming,可以說是本人一直沒有啃下的骨頭,這次我就得好好來學學Dynamic programming.
OK,出發!
動態規劃通常是分治演算法的一種特殊情況,它一般用於最優化問題,如果這些問題能夠:
1.能夠分解為規模更小的子問題
2.遞迴的子問題具有最優子結構性質。也就是說,原問題的最優化解能夠通過子問題的解計算得到。
動態規劃的一個核心的步驟就是定義一個合適的問題形式,動態規劃與分治演算法不一樣,動態規劃演算法通常需要列舉所有的可能的切分策略,這是因為需要得到最優解;除此之外,動態規劃通過“記錄已計運算元問題的解”來避免重複計算。
為了使用動態規劃的方法,那麼我們首先得先看問題能夠使用分治的方法來解決。給定一個問題,我們需要先看看他的核心輸入資料結構是否可以分解。如果發現輸入的核心資料結構為:
- 陣列
- 矩陣
- 集合
- 樹
- 圖
那麼這些輸入是很容易分解的。
我們再看,子問題的輸出能夠構成原問題的輸出。
如果上面兩個條件都滿足,那麼這個問題當然是可以使用分治法來解決的。
下面,我們通過幾個經典的問題來看看如何由分治過渡到動態規劃。
矩陣連乘問題
INPUT:
給定:
n個矩陣,矩陣
的形狀為
OUTPUT:
給出一個
的運算順序,使得乘法的次數最少。
先看看為啥不同運算順序,會造成乘法的次數不一樣呢?
假設有三個矩陣:
那麼第一種運算順序:
,需要的乘法次數為:1x2x3+1x3x4=18
第二種運算順序:
,需要的乘法次數為2x3x4+1x2x4=32。
那麼第一種運算次數更少,因此第一種運算順序更好。
當直接給n個矩陣的時候,我們是不好下手的,也沒有啥頭緒。那我們就想,
我們就先看n=1,2,3,4的時候嘛。
當n=1的時候,不要乘了。
當只有2個矩陣相乘的時候,沒有什麼最優的,就只有一種運算順序,我們看到會做的;
當只有3個矩陣相乘的時候,我們也會做的,就是隻要像上面的例子一樣去比較就是了的。
當有四個矩陣的時候呢?能不能劃為先三個矩陣相乘再兩個矩陣相乘?或者左邊兩個矩陣,右邊兩個矩陣,兩個中間結果再乘起來?因為,我們會做2個和3個矩陣相乘了。
當有5個矩陣呢?
我們看到,當n很小的時候,我們是會做的。那麼給定一個很大的n,我們能不能把它轉換為規模更小的n呢?
假設我們把這個問題看做一個多階段決策問題,每次的決策就是選一個位置加一個括號。
OK,假設我們已經得到最優的解了。那麼這個最優解的最後一次乘法,一定可以看成是兩個部分的乘積。也就是說從:
選擇一個k,使得最終的結果是從:
兩部分乘積得到。
這下子好了,左邊的連乘就是
,這個問題和原問題很像啊,就是規模改了一下,內容不一樣而已。右邊也是類似的。
然後,我們先解決
,顯然這個問題,也可以看成最後由兩個矩陣乘積得到,也就是要選擇一個j使得:
等等···
經過若干次的分析以後,我們就開始看到我們所要解決問題的通用形式了:尋找某個執行順序,使得
的乘法次數最少。定義
表示
所需的最少的乘法次數。原問題其實就是在求
而將原問題分解為兩個子問題: 和 ,那麼原問題的解可以通過 得到。
這是因為左邊 得到一個