0-1背包問題

問題描述:

0-1背包問題:給定n種物品和一背包。物品 i 的重量似乎 wi,其價值為 vi,背包的容量為 c。問應該如何選擇裝入背包中的物品,使得裝入背包中物品的總價值最大?

說實在的,書上講的東西生澀難懂,我更偏向于看一些有趣的東西。我們來換一個風格來描述這一個問題。
以下內容大部分來自《算法圖解》一書。看完之后大有收獲。

另一種風格的描述:

假設你是一個小偷,背著一個可裝下4磅東西的背包,你可以偷竊的物品如下:

為了讓偷竊的商品價值最高,你該選擇哪些商品?

簡單算法

最簡單的算法是:嘗試各種可能的商品組合,并找出價值最高的組合。

這樣顯然是可行的,但是速度非常慢。在只有3件商品的情況下,你需要計算8個不同的集合;當有4件商品的時候,你需要計算16個不同的集合。每增加一件商品,需要計算的集合數都將翻倍!這種算法的運行時間是O(2?),真的是慢如蝸牛。

動態規劃

解決這樣問題的答案就是使用動態規劃!下面來看看動態規劃的工作原理。動態規劃先解決子問題,再逐步解決大問題。

對于背包問題,你先解決小背包(子背包)問題,再逐步解決原來的問題。

比較有趣的一句話是:每個動態規劃都從一個網格開始。

背包問題的網格如下:

網格的各行為商品,各列為不同容量(1~4磅)的背包。所有這些列你都需要,因為它們將幫助你計算子背包的價值。

網格最初是空的。你將填充其中的每個單元格,網格填滿后,就找到了問題的答案!

1.吉他行

后面會列出計算這個網格中單元格值得公式,但現在我們先來一步一步做。首先來看第一行。

這是吉他行,意味著你將嘗試將吉他裝入背包。在每個單元格,都需要做一個簡單的決定:偷不偷吉他?別忘了,你要找出一個價值最高的商品集合。

第一個單元格表示背包的的容量為1磅。吉他的重量也是1磅,這意味著它能裝入背包!因此這個單元格包含吉他,價值為1500美元。

下面來填充網格。

與這個單元格一樣,每個單元格都將包含當前可裝入背包的所有商品。

來看下一個單元格。這個單元格表示背包容量為2磅,完全能夠裝下吉他!

這行的其他單元格也一樣。別忘了,這是第一行,只有吉他可供你選擇,換而言之,你假裝現在還沒發偷竊其他兩件商品。

此時你很可能心存疑惑:原來的問題說的額是4磅的背包,我們為何要考慮容量為1磅、2磅等得背包呢?前面說過,動態規劃從小問題著手,逐步解決大問題。這里解決的子問題將幫助你解決大問題。

別忘了,你要做的是讓背包中商品的價值最大。這行表示的是當前的最大價值。它指出,如果你有一個容量4磅的背包,可在其中裝入的商品的最大價值為1500美元。

你知道這不是最終解。隨著算法往下執行,你將逐步修改最大價值。

2.音響行

我們來填充下一行——音響行。你現在處于第二行,可以偷竊的商品有吉他和音響。

我們先來看第一個單元格,它表示容量為1磅的背包。在此之前,可裝入1磅背包的商品最大價值為1500美元。

該不該偷音響呢?

背包的容量為1磅,顯然不能裝下音響。由于容量為1磅的背包裝不下音響,因此最大價值依然是1500美元。

接下來的兩個單元格的情況與此相同。在這些單元格中,背包的容量分別為2磅和3磅,而以前的最大價值為1500美元。由于這些背包裝不下音響,因此最大的價值保持不變。

背包容量為4磅呢?終于能夠裝下音響了!原來最大價值為1500美元,但如果在背包中裝入音響而不是吉他,價值將為3000美元!因此還是偷音響吧。

你更新了最大價值。如果背包的容量為4磅,就能裝入價值至少3000美元的商品。在這個網格中,你逐步地更新最大價值。

3.筆記本電腦行

下面以同樣的方式處理筆記本電腦。筆記本電腦重3磅,沒法將其裝入1磅或者2磅的背包,因此前兩個單元格的最大價值仍然是1500美元。

對于容量為3磅的背包,原來的最大價值為1500美元,但現在你可以選擇偷竊價值2000美元的筆記本電腦而不是吉他,這樣新的最大價值將為2000美元。

對于容量為4磅的背包,情況很有趣。這是非常重要的部分。當前的最大價值為3000美元,你可不偷音響,而偷筆記本電腦,但它只值2000美元。

價值沒有原來高,但是等一等,筆記本電腦的重量只有3磅,背包還有1磅的重量沒用!

在1磅的容量中,可裝入的商品的最大價值是多少呢?你之前計算過。

根據之前計算的最大價值可知,在1磅的容量中可裝入吉他,價值1500美元。因此,你需要做如下的比較:

你可能始終心存疑惑:為何計算小背包可裝入的商品的最大價值呢?但愿你現在明白了其中的原因!余下了空間時,你可根據這些子問題的答案來確定余下的空間可裝入哪些商品。筆記本電腦和吉他的總價值為3500美元,因此偷它們是更好的選擇。

最終的網格類似于下面這樣。

答案如下:將吉他和筆記本電腦裝入背包時價值更高,為3500美元。

你可能認為,計算最后一個單元格的價值時,我使用了不同的公式。那是因為填充之前的單元格時,我故意避開了一些復雜的因素。其實,計算每個單元格的價值時,使用的公式都相同。這個公式如下。

你可以使用這個公式來計算每個單元格的價值,最終的網格將與前一個網格相同。現在你明白了為何要求解子問題了吧?你可以合并兩個子問題的解來得到更大問題的解。

代碼實現:

算法的核心是思想,當清楚了整個過程,那么寫代碼就簡單了,直接來模擬上述的一個過程:

/**
 * @author:我沒有三顆心臟
 * @create:2017-11-14-10:24
 */
public class MaxBag {
    static int n;           // 描述物品個數
    static int c;           // 描述背包容量
    static int[] value;     // 描述物品價值
    static int[] weight;    // 描述物品重量

    public static void main(String[] args) {
        // 初始賦值操作
        value = new int[]{1500, 3000, 2000};
        weight = new int[]{1, 4, 3};
        c = 4;
        n = 3;

        // 構造最優解的網格:3行4列
        int[][] maxValue = new int[n][c];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < c; j++) {
                maxValue[i][j] = 0;
            }
        }   // end for

        // 填充網格
        for (int i = 0; i < n; i++) {
            for (int j = 1; j <= c; j++) {
                if (i == 0) {
                    maxValue[i][j - 1] = (weight[i] <= j ? value[i] : 0);
                } else {
                    int topValue = maxValue[i - 1][j - 1];  // 上一個網格的值
                    int thisValue = (weight[i] <= j ?       // 當前商品的價值 + 剩余空間的價值
                            (j - weight[i] > 0 ? value[i] + maxValue[i - 1][j - weight[i]] : value[i])
                            : topValue);

                    // 返回 topValue和thisValue中較大的一個
                    maxValue[i][j - 1] = (topValue > thisValue ? topValue : thisValue);
                }   // end if
            }   // end inner for
        }   // end outer for

        // 打印結果二維數組maxValue
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < c; j++) {
                System.out.printf("%6d", maxValue[i][j]);
            }
            System.out.println();
        }
    }
}

最后打印出來的結果如下:

再增加一件商品將如何呢

假設你發現還有第四件商品可偷——一個iPhone!(或許你會毫不猶豫的拿走,但是請別忘了問題的本身是要拿走價值最大的商品)

此時需要重新執行前面所做的計算嗎?不需要。別忘了,動態規劃逐步計算最大價值。到目前為止,計算出的最大價值如下:

這意味著背包容量為4磅時,你最多可偷價值3500美元的商品。但這是以前的情況,下面再添加表示iPhone的行。

我們還是從第一個單元格開始。iPhone可裝入容量為1磅的背包。之前的最大價值為1500美元,但iPhone價值2000美元,因此該偷iPhone而不是吉他。

在下一個單元格中,你可裝入iPhone和吉他。

對于第三個單元格,也沒有比裝入iPhone和吉他更好的選擇了。

對于最后一個單元格,情況比較有趣。當前的最大價值為3500美元,但你可以偷iPhone,這將余下3磅的容量。

3磅容量的最大價值為2000美元!再加上iPhone價值2000美元,總價值為4000美元。新的最大價值誕生了!

最終的網格如下。

問題:沿著一列往下走,最大價值可能降低嗎?

答案是:不可能。因為每次迭代時,你都存儲的是當前的最大價值。最大價值不可能比以前低!

總結:

有時候教科書生澀難懂,你需要找一些更好的資料來幫助你學習,更重要的一點是,保持一顆好奇心還有求知欲。

歡迎轉載,轉載請注明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關注公眾微信號:wmyskxz_javaweb
分享自己的Java Web學習之路以及各種Java學習資料

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