算法小專欄:動態(tài)規(guī)劃(一)

級別: ★☆☆☆☆
標簽:「算法」「DP策略」「動態(tài)規(guī)劃」
作者: MrLiuQ
審校: QiShare團隊


本篇將介紹動態(tài)規(guī)劃相關(guān)知識。

一、簡介

動態(tài)規(guī)劃(Dynamic Programming,簡稱DP)。

它的核心思想是把一個復雜的大問題拆成若干個子問題,通過解決子問題來逐步解決大問題

注意:使用動態(tài)規(guī)劃思想有個前提:當且僅當每個子問題都是離散的(即每個子問題都不依賴于其他子問題時),才能使用動態(tài)規(guī)劃。


二、動態(tài)規(guī)劃之“0-1背包問題”

現(xiàn)在有這么一個場景,
“你”是一名“小偷”,你帶了個包去“偷東西”,。

條件1:每個商品只有一個,要么拿,要么不拿。(0-1背包問題)
條件2:你最多拿得動4kg的東西。(固定大小,可不裝滿)

商品 價格 重量
商品A 3000元 4kg
商品B 2000元 3kg
商品C 1500元 1kg
商品D 2000元 1kg

有限的重量條件下,如何“偷”,賺的錢最多?

方案一:簡單算法(可行,不推薦)

暴力枚舉出所有商品的排列組合,
舍去所有超出重量要求的組合,
從中挑一個最大的。

可行,但是太慢了,每多一件商品都會多2倍的組合。

方案測評:時間復雜度 O(2n),超級超級慢,不推薦。

方案二:貪心算法(不可行)

用上篇介紹的貪心算法計算。

通過某個貪心策略(拿最貴的、拿性價比最高的商品)來得出近似解。

方案測評:這種方案接近最優(yōu)解,是近似解,但不一定是最優(yōu)解,故不可行。

方案三:動態(tài)規(guī)劃(可行,推薦)
  • 原理:先解決子背包最優(yōu),再解決大背包最優(yōu)。

先繪制出一張表格,一會我們一列一列慢慢填。(PS:體會動態(tài)規(guī)劃的算法過程)

表格:(實際上對應了一個二維數(shù)組)

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A
商品B
商品C
商品D

先解讀一下這個表格,
行:代表了商品行(對應i),
列:代表了重量列(對應j),
格:代表當前的已有的商品、已有重量下所能拿的最大價值

好了,下面我們開始一列一列的填:

第一行,只有商品A(價值:3000,重量:4kg)

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A /
商品B
商品C
商品D

第二行,有商品A(價值:3000,重量:4kg)與商品B(價值:2000,重量:3kg)

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A /
商品B /
商品C
商品D

第三行,有商品A(價值:3000,重量:4kg)、商品B(價值:2000,重量:3kg)商品C(價值:1500,重量:1kg)

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A /
商品B /
商品C 1500
商品D

第四行,有商品A(價值:3000,重量:4kg)、商品B(價值:2000,重量:3kg)、商品C(價值:1500,重量:1kg)、商品D(價值:2000,重量:1kg)

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A /
商品B /
商品C 1500
商品D 2000

大家有沒有發(fā)現(xiàn),這里填寫每個表格時的算法可表示為:

對應行的商品的重量超過當前子背包的重量,就取上一行單元格的值,
商品的重量能裝下當前子背包,則取下面兩者的較大值:

  • 上一個單元格的值(cell[i-1][j]
  • 當前商品的價值 + 剩余空間的價值(cell[i-1][j-當前商品的重量所對應的列號]

下面填第二列:

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A / /
商品B / /
商品C 1500 1500
商品D 2000 3500

第三列:

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A / / /
商品B / / 2000
商品C 1500 1500 2000
商品D 2000 3500 3500

第四列:

商品\ 子背包最大重量 1kg 2kg 3kg 4kg
商品A / / / 3000
商品B / / 2000 3000
商品C 1500 1500 2000 3500
商品D 2000 3500 3500 4000

于此反復判斷即可,這樣每個單元格都是最優(yōu)解,通過解決子問題,推導出最終最優(yōu)解。
這就是動態(tài)規(guī)劃,是不是很簡單呢?

轉(zhuǎn)換成Python代碼:

def package_dp(a, b, flag, n):
    c = [[0 for i in range(n)] for j in range(n)]
    for j in range(n):
        c[0][j] = 0

    for i in range(n):
        c[i][0] = 0
        for j in range(n):
            if b[i]>flag[j]:
                c[i][j] = c[i-1][j]
            else:
                temp1 = a[i] + c[i-1][j-b[i]]
                temp2 = c[i-1][j]
                c[i][j] = max(temp1,temp2)
            print c[i][j]
        print ("")
    return c

price = [0, 3000, 2000, 1500, 2000]
weight = [0, 4, 3, 1, 1]
flag = [0, 1, 2, 3, 4]

package_dp(price, weight, flag, 5)

三、細節(jié)問題

  • 子背包拆分問題:按照 所有商品 的最大公約數(shù)(也有可能存在小數(shù))去拆子背包。
    讓所有的商品都能被剛好裝下。

  • 通過子背包的最優(yōu)解 => 推導出 => 全背包的最優(yōu)解。
    這個過程的思想,就是DP思想(動態(tài)規(guī)劃的核心思想)


四、動態(tài)規(guī)劃的應用場景

本文舉了背包與矩陣連乘的例子,其實思路都是一樣的。
只是應用場景不同,常見的應用場景有以下幾個:

  • 0-1背包問題( ??)
  • 矩陣連乘法( ??)
  • 硬幣找零
  • 字符串相似度
  • 最長公共子序列
  • 最長遞增子序列
  • 最大連續(xù)子序列和/積
  • 有代價的最短路徑
  • 瓷磚覆蓋(狀態(tài)壓縮DP)
  • 工作量劃分

參考資料:


推薦文章:
Dart基礎(chǔ)(一)
Dart基礎(chǔ)(二)
Dart基礎(chǔ)(三)
Dart基礎(chǔ)(四)
iOS 短信驗證碼倒計時按鈕
iOS 環(huán)境變量配置
iOS 中處理定時任務的常用方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內(nèi)容