《數(shù)據(jù)結(jié)構(gòu)與算法之美》28——?jiǎng)討B(tài)規(guī)劃理論

前言

上一節(jié)通過兩個(gè)經(jīng)理案例初步認(rèn)識(shí)動(dòng)態(tài)規(guī)劃颤诀,今天這一節(jié)主要講動(dòng)態(tài)規(guī)劃的理論知識(shí)。

“一個(gè)模型三個(gè)特征”理論講解

實(shí)際上,動(dòng)態(tài)規(guī)劃作為一個(gè)非常成熟的算法思想温亲,這部分理論總結(jié)為“一個(gè)模型三個(gè)特征”。

一個(gè)模型

一個(gè)模型指動(dòng)態(tài)規(guī)劃適合解決的問題模型杯矩。這個(gè)模型定義為“多階段決策最優(yōu)解模型”栈虚。

一般是用動(dòng)態(tài)規(guī)劃來解決最優(yōu)問題。而解決問題的過程史隆,需要經(jīng)歷多個(gè)決策階段魂务。每個(gè)決策階段都對(duì)應(yīng)著一組狀態(tài)。然后尋找一組決策序列泌射,經(jīng)過這組決策序列粘姜,能夠產(chǎn)生最終期望求解的值。

三個(gè)特征

三個(gè)特征分別是:最優(yōu)子結(jié)構(gòu)熔酷、無后效性重復(fù)子問題孤紧。

  • 最優(yōu)子結(jié)構(gòu):?jiǎn)栴}的最優(yōu)解包含子問題的最優(yōu)解。
  • 無后效性:有兩層含義拒秘。
    1. 第一層号显,在推導(dǎo)后面階段的狀態(tài)時(shí),只關(guān)心前面階段的狀態(tài)值翼抠。
    2. 第二層咙轩,某階段的狀態(tài)一旦確定,就不受之后階段的決策影響阴颖。
  • 重復(fù)子問題:不同的決策序列活喊,到達(dá)某個(gè)相同的階段時(shí),可能會(huì)產(chǎn)生重復(fù)的狀態(tài)量愧。

兩種動(dòng)態(tài)規(guī)劃解題思路總結(jié)

解決動(dòng)態(tài)規(guī)劃問題钾菊,一般有兩種思路。分別是狀態(tài)轉(zhuǎn)移表法狀態(tài)轉(zhuǎn)移方程法偎肃。

狀態(tài)轉(zhuǎn)移表法

狀態(tài)轉(zhuǎn)移表法的解題思路概括為:回溯算法實(shí)現(xiàn)-定義狀態(tài)-畫遞歸樹-找重復(fù)子問題-畫狀態(tài)轉(zhuǎn)移表-根據(jù)遞推關(guān)系填表-將填表過程翻譯成代碼煞烫。

我們來看一下,如何套用狀態(tài)轉(zhuǎn)移表法來解決動(dòng)態(tài)規(guī)劃問題累颂。

假設(shè)我們有一個(gè)n乘以n的矩陣w[n][n]滞详。矩陣存儲(chǔ)的都是正整數(shù)凛俱。棋子起始位置在左上角,終止位置在右下角料饥。那從左上角移動(dòng)到右下角的最短路徑長(zhǎng)度是多少蒲犬?

二維矩陣

回溯算法實(shí)現(xiàn)

public class Solution {
    private int minDist = int.MaxValue;
    public int MinDist { get { return minDist; } }
    // 調(diào)用方式:MinDistBT(0, 0, 0, w, n);
    public void MinDistBT (int i, int j, int dist, int[][] w, int n) {
        // 到達(dá)n-1, n-1這個(gè)位置了
        if (i == n - 1 && j == n - 1) {
            dist = dist + w[i][j];
            if (dist < minDist) minDist = dist;
            return;
        }

        if (i < n - 1) { // 往下走,更新i=i+1, j=j
            MinDistBT (i + 1, j, dist + w[i][j], w, n);
        }
        if (j < n - 1) { // 往右走岸啡,更新i=i, j=j+1
            MinDistBT (i, j + 1, dist + w[i][j], w, n);
        }
    }
}

定義狀態(tài)

從回溯代碼的函數(shù)調(diào)用可知原叮,每一個(gè)狀態(tài)包含三個(gè)變量(i, j, dist),其中 i巡蘸,j 分別表示行和列奋隶,dist 表示從起點(diǎn)到達(dá)(i, j)的路徑長(zhǎng)度。

畫遞歸樹

有了回溯代碼和狀態(tài)定義悦荒,把每個(gè)狀態(tài)作為一個(gè)節(jié)點(diǎn)唯欣,畫出遞歸樹。

遞歸樹

找重復(fù)子問題

從上圖可知搬味,存在重復(fù)子問題黍聂。

畫狀態(tài)轉(zhuǎn)移表

我們畫出一個(gè)二維狀態(tài)表,表中的行身腻、列表示棋子所在的位置产还,表中的數(shù)值表示從起點(diǎn)到這個(gè)位置的最短路徑。

根據(jù)遞推關(guān)系填表

按照決策過程嘀趟,通過不斷狀態(tài)遞推演進(jìn)脐区,將狀態(tài)表填好。

填表

將填表過程翻譯成代碼

public class Solution2 {
    public int MinDistDP (int[][] matrix, int n) {
        int[][] states = new int[n][];
        for (int i = 0; i < n; i++) {
            states[i] = new int[n];
        }

        int sum = 0;
        for (int j = 0; j < n; ++j) { // 初始化states的第一行數(shù)據(jù)
            sum += matrix[0][j];
            states[0][j] = sum;
        }
        sum = 0;
        for (int i = 0; i < n; ++i) { // 初始化states的第一列數(shù)據(jù)
            sum += matrix[i][0];
            states[i][0] = sum;
        }

        for (int i = 1; i < n; ++i) {
            for (int j = 1; j < n; ++j) {
                states[i][j] = matrix[i][j] + Math.Min (states[i][j - 1], states[i - 1][j]);
            }
        }
        return states[n - 1][n - 1];
    }
}

狀態(tài)轉(zhuǎn)移方程法

狀態(tài)轉(zhuǎn)移方程法的解題思路概括為:找最優(yōu)子結(jié)構(gòu)-寫狀態(tài)轉(zhuǎn)移方程-將狀態(tài)轉(zhuǎn)移方程翻譯成代碼她按。

還是拿上面的例子來說明牛隅。

找最優(yōu)子結(jié)構(gòu)

min_dist(i, j)可以通過min_dist(i, j-1)和min_dist(i-1, j)兩個(gè)狀態(tài)推導(dǎo)出來,符合“最優(yōu)子結(jié)構(gòu)”酌泰。

寫狀態(tài)轉(zhuǎn)移方程

min_dist(i, j) = w[i][j] + min(min_dist(i, j-1), min_dist(i-1, j))

強(qiáng)調(diào)一下媒佣,狀態(tài)轉(zhuǎn)移方程是解決動(dòng)態(tài)規(guī)劃的關(guān)鍵

將狀態(tài)轉(zhuǎn)移方程翻譯成代碼

一般情況下陵刹,有兩種代碼實(shí)現(xiàn)方法:

  • 遞歸+“備忘錄”
  • 迭代遞推

用遞歸+“備忘錄”將狀態(tài)轉(zhuǎn)移方程翻譯成代碼默伍。

public class Solution3 {
    private int[, ] matrix = new int[4, 4] { { 1, 3, 5, 9 }, { 2, 1, 3, 4 }, { 5, 2, 6, 7 }, { 6, 8, 4, 3 } };

    private int n = 4;
    private int[, ] mem = new int[4, 4];

    public int MinDist (int i, int j) { // 調(diào)用MinDist(n-1, n-1)
        if (i == 0 && j == 0) return matrix[0, 0];
        if (mem[i, j] > 0) return mem[i, j];
        int minLeft = int.MaxValue;
        if (j - 1 >= 0) {
            minLeft = MinDist (i, j - 1);
        }
        int minUp = int.MaxValue;
        if (i - 1 >= 0) {
            minUp = MinDist (i - 1, j);
        }

        int curMinDist = matrix[i, j] + Math.Min (minLeft, minUp);
        mem[i, j] = curMinDist;
        return curMinDist;
    }
}

總結(jié)

動(dòng)態(tài)規(guī)劃有兩種解題思路:狀態(tài)轉(zhuǎn)移表法和狀態(tài)轉(zhuǎn)移方程法。

狀態(tài)轉(zhuǎn)移表法的解題思路概括為:回溯算法實(shí)現(xiàn)-定義狀態(tài)-畫遞歸樹-找重復(fù)子問題-畫狀態(tài)轉(zhuǎn)移表-根據(jù)遞推關(guān)系填表-將填表過程翻譯成代碼衰琐。

狀態(tài)轉(zhuǎn)移方程法的解題思路概括為:找最優(yōu)子結(jié)構(gòu)-寫狀態(tài)轉(zhuǎn)移方程-將狀態(tài)轉(zhuǎn)移方程翻譯成代碼也糊。

參考資料

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羡宙,一起剝皮案震驚了整個(gè)濱河市狸剃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狗热,老刑警劉巖钞馁,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虑省,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡僧凰,警方通過查閱死者的電腦和手機(jī)慷妙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來允悦,“玉大人,你說我怎么就攤上這事虑啤∠冻冢” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵狞山,是天一觀的道長(zhǎng)全闷。 經(jīng)常有香客問我,道長(zhǎng)萍启,這世上最難降的妖魔是什么总珠? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮勘纯,結(jié)果婚禮上局服,老公的妹妹穿的比我還像新娘。我一直安慰自己驳遵,他們只是感情好淫奔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著堤结,像睡著了一般唆迁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上竞穷,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天唐责,我揣著相機(jī)與錄音,去河邊找鬼瘾带。 笑死鼠哥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的看政。 我是一名探鬼主播肴盏,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼帽衙!你這毒婦竟也來了菜皂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤厉萝,失蹤者是張志新(化名)和其女友劉穎恍飘,沒想到半個(gè)月后榨崩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡章母,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年母蛛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乳怎。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彩郊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蚪缀,到底是詐尸還是另有隱情秫逝,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布询枚,位于F島的核電站违帆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏金蜀。R本人自食惡果不足惜刷后,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渊抄。 院中可真熱鬧尝胆,春花似錦、人聲如沸护桦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嘶炭。三九已至抱慌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眨猎,已是汗流浹背抑进。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留睡陪,地道東北人寺渗。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兰迫,于是被迫代替她去往敵國(guó)和親信殊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355