一文讀懂背包問題

2021-03-02 算法愛好者
(點擊上方公眾號,可快速關注)

轉自:劉毅

https://www.61mon.com/index.php/archives/188/

好文投稿, 請點擊 → 這裡了解詳情


問題展開

有 N 件物品和一個容量為 V 的背包。第 i 件物品的體積是 Ci,其價值是 Wi。求解,在不超過背包容量情況下,將哪些物品裝入背包可使價值總和最大。


基本思路

這是最基礎的背包問題,特點是:每種物品僅有一件。

狀態 F[i,v] 表示前 i 件物品中選擇若干件放在容量為 v 的背包中,可以取得的最大價值。

轉移方程:

對於第 i 件物品,有放與不放兩種選擇。若選擇不放,F[i,v]=F[i−1,v];若選擇放,v−Ci 確保有足夠的空間,隨之 F[i,v]=F[i−1,v−Ci]+Wi。

代碼展開

/**

 *

 * author 劉毅(Limer)

 * date   2017-03-17

 * mode   C++

 */

#include <iostream>

#include <algorithm>

using namespace std;

int main()

{

    const int N = 6;                     // 物品個數

    const int V = 10;                    // 背包體積

     // 第 i 個物品的體積(下標從 1 開始)

    int C[N + 1] = { -1,5,6,5,1,19,7 }; 

     // 第 i 個物品的價值

    int W[N + 1] = { -1,2,3,1,4,6,5 };   

     // 狀態

    int F[N + 1][V + 1] = { 0 };        

    // 對於第 i 個物品

    for (int i = 1; i <= N; i++) 

        for (int v = 0; v <= V; v++)

        {

            F[i][v] = F[i - 1][v];  //第 i 個不放

            // 如果比它大,再放第 i 個

            if (v - C[i] >= 0 && F[i][v] < F[i - 1][v - C[i]] + W[i])                 

                   F[i][v] = F[i - 1][v - C[i]] + W[i];

        }

    cout<< F[N][V] << endl;  

    return 0;

}

以上方法的時間和空間複雜度均為 O(VN),其中時間複雜度應該已經不能再優化了,但空間複雜度卻可以優化到 O(V)。

先考慮上面講的基本思路如何實現,肯定是有一個主循環i ← 1 to N,每次算出來二維數組 F[i,v] 的所有值。

那麼,如果只用一個數組 F[v] 能不能保證第 i 次循環結束後 F[v] 中表示的就是我們定義的狀態 F[i,v] 呢?

F[i,v] 是由 F[i−1,v] 和 F[i−1,v−Ci] 兩個子問題遞推而來,能否保證在推 F[i,v] 時(也即在第 i 次主循環中推 F[v] 時)能夠取用 F[i−1,v] 和 F[i−1,v−Ci] 的值呢?

事實上,這要求在每次主循環中我們以v ← V to C[i]的遞減順序計算 F[v],這樣才能保證計算 F[v] 時 F[v−Ci] 保存的是狀態 F[i−1,v−Ci] 的值。

優化後的代碼如下:

/**

 *

 * author 劉毅(Limer)

 * date   2017-03-17

 * mode   C++

 */

#include <iostream>

#include <algorithm>

using namespace std;

int main()

{

    const int N = 6;                     // 物品個數

    const int V = 10;                    // 背包體積

    // 第 i 個物品的體積(下標從 1 開始)

    int C[N + 1] = { -1,5,6,5,1,19,7 };  

    // 第 i 個物品的價值

    int W[N + 1] = { -1,2,3,1,4,6,5 };  

    int F[V + 1] = { 0 };                // 狀態

    for (int i = 1; i <= N; i++)  // 對於第 i 個物品

        for (int v = V; v >= C[i]; v--)

            F[v] = max(F[v], F[v - C[i]] + W[i]);

    cout << "最大價值是:" << F[V] << endl;  

    return 0;

}

初始化的細節問題

我們看到的求最優解的背包問題題目中,事實上有兩種不太相同的問法。有的題目要求 「恰好裝滿背包」 時的最優解,有的題目則並沒有要求必須把背包裝滿。

這兩種問法的實現方法只是在初始化的時候有所不同。

如果是第一種問法,要求恰好裝滿背包,那麼在初始化時除了 F[0] 為 0,其它 F[1]...F[V] 均設為−∞,這樣就可以保證最終得到的 F[V] 是一種恰好裝滿背包的最優解。

如果並沒有要求必須把背包裝滿,而是只希望價格儘量大,初始化時應該將 F[0]...F[V] 全部設為 0。

這是為什麼呢?可以這樣理解:初始化的 F 數組事實上就是在沒有任何物品可以放入背包時的合法狀態。

如果要求背包恰好裝滿,那麼此時只有容量為 0 的背包可以在什麼也不裝且價值為 0 的情況下被 「恰好裝滿」,其它容量的背包均沒有合法的解,屬於未定義的狀態,應該被賦值為 -∞了。

如果背包並非必須被裝滿,那麼任何容量的背包都有一個合法解 「什麼都不裝」,這個解的價值為 0,所以初始時狀態的值也就全部為 0 了。

參考文獻

背包九講.

覺得本文有幫助?請分享給更多人

關注「算法愛好者」,修煉編程內功

相關焦點

  • Python|動態規劃|0-1背包問題
    前言對學算法的同學來說,動態規劃是其必學且較為重要的問題之一;其中0-1背包問題是最經典的動態規劃問題;本博客也主要以動態規劃來解決0-1背包問題。問題描述有如下的背包的重量及其所對應的質量,背包的最大承受重量為6kg,試問要怎樣裝入才能使得背包再最大的承受重量的範圍內裝入的物品的質量最大?
  • 一文讀懂婚姻中的財產劃分
    一文讀懂婚姻中的財產劃分 2020-05-16 02:25 來源:澎湃新聞·澎湃號·政務
  • 一文讀懂:高尿酸血症怎麼治療
    原創 李青大夫 腎病科普 來自專輯痛風一文讀懂:高尿酸血症怎麼治療天津市泰達醫院 李青一、什麼是高尿酸血症:正常飲食狀態下,兩次空腹檢測血尿酸水平,女>360μmol/L(6mg/dL)、男>420μmol/L(7mg/dL),就診斷為高尿酸血症。
  • 上了老羅直播間,原來文青背包長這樣,LEVEL8文青背包圖賞
    就在上個月,老羅便在直播間手把手推薦了地平線8號(LEVEL 8)剛上線的文青背包。雖說坑位費不會少,但能入老羅眼肯定不一般,所以我在第一時間也入了這款背包,到手後發現果然與傳統有點不一樣,下面就為大家做一個簡單的上手體驗。
  • PHP 0-1背包問題
    0-1背包問題背景我們有n種物品,物品j的重量為wj,價格為pj。我們假定所有物品的重量和價格都是非負的。背包所能承受的最大重量為W。如果限定每種物品只能選擇0個或1個,則問題稱為0-1背包問題。背包問題遞歸算法假如背包的容量是C=6,物品的體積為w,對應的物品的價值為v。我們從最後一個物品開始,如果它的體積比背包剩餘容量小,它面臨著兩種選擇:1,放進背包;2,不放進背包。
  • 背包問題-動態規劃java實現代碼
    20世紀50年代初美國數學家R.E.Bellman等人在研究多階段決策過程(multistep decision process)的優化問題時,提出了著名的最優化原理(principle of optimality),把多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解,創立了解決這類過程優化問題的新方法–動態規劃。
  • 操作流程一文讀懂
    操作流程一文讀懂 2020-12-26 18:08 來源:澎湃新聞·澎湃號·政務
  • 一圖讀懂丨關於離婚糾紛問題,法律講堂開課啦!
    一圖讀懂丨關於離婚糾紛問題,法律講堂開課啦!來 源市婦聯權益部原標題:《一圖讀懂丨關於離婚糾紛問題,法律講堂開課啦!》
  • 【深度】一文讀懂印度農民抗議問題
    但問題在於,政府保障機制完全退出、讓大企業和自由市場機製取而代之,是否就是矯正這種扭曲最佳的辦法呢?或者說,徹底廢除MSP,是否就能讓這些問題都自然消失呢?
  • 動態規劃:關於01背包問題,你該了解這些!(滾動數組)
    昨天動態規劃:關於01背包問題,你該了解這些!中是用二維dp數組來講解01背包。今天我們就來說一說滾動數組,其實在前面的題目中我們已經用到過滾動數組了,就是把二維dp降為一維dp,一些錄友當時還表示比較困惑。
  • 出行最後一公裡難?Impossible從背包裡掏出了自行車
    【獵雲網(微信號:ilieyun)深圳】10月27日報導(文/邱瑤)在出行最後一公裡的領域,當ofo和摩拜單車擼起袖子準備來一場「橙黃大戰」的時候,Impossible科技已經從背包拿出自行車,騎車「上班」去了。
  • 《口袋妖怪GO》背包滿解決方案教學 常見問題解答
    導 讀 口袋妖怪GO國服遲遲沒有上線~那麼口袋妖怪玩法是什麼~背包滿了怎麼辦呢~一起跟著小編來看看。
  • 坐騎大集合,5151《神仙道》解決你的背包問題
    5151《神仙道》更新後,不少修仙者進入遊戲後發現自己的坐騎不見了,甚至從商店重新購買也消失不見,這等詭異現象莫不是出BUG了?  大家都知道,在以前,坐騎都是放在背包裡的,假如是坐騎控,各種坐騎放在背包裡,那可真是佔格子……如今坐騎專用欄一出,完美解決修仙者們背包位置不夠的問題,另外,5151《神仙道》此番更新還新增了一款拉風坐騎——雪狼,雖然不能增添修仙者們的各項屬性
  • 一文讓你讀懂CEFR與雅思、託福、劍橋的關係!
    一文讓你讀懂CEFR與雅思、託福、劍橋的關係!因此,CEFR課程是否獲得了第三方權威認證,是否符合歐盟標準等是家長們必須關注的首要問題。經過對在線少兒英語機構的調研與審查,阿卡索的CEFR課程是獲得了英國權威機構免責聲明:市場有風險,選擇需謹慎!此文僅供參考,不作買賣依據。
  • 小學生讀懂《哈利波特》英文原版!靈魂拷問:怎樣才算讀懂一本書
    有小夥伴說六七歲就能讀懂了,有高中生說高中了還讀不懂,有的說讀懂《哈利波特》英文版一點都不難,有的說除了咒語外其他一概看不懂,還有的說:這群孩子太嘚瑟,小小年級居然敢說自己讀懂了……我還看到,三四百條的激烈討論背後,是上萬人的閱讀,也有三四百人悄悄地收藏學習。只有一小波的焦點落在「讀懂」的判斷上。
  • 【一夢芳菲】讀懂最重要
    > 作者:大象 圖片:網絡 編輯:一夢芳菲 《讀懂最重要》 文:大象 有人說歲月靜好,有人說歲月如梭,有人說歲月如刀!
  • 一文讀懂暖奶器暖奶的正確方法
    原標題:一文讀懂暖奶器暖奶的正確方法暖奶器顧名思義是用來給寶寶暖奶的。尚處於哺乳期的寶寶身體嬌弱,對奶液的溫度要求較高。一、熱奶保溫熱奶保溫功能有助於保持奶液溫度,蘇泊爾暖奶器默認暖奶溫度是40℃,溫度調節範圍35-45℃,最長工作時間90分鐘。
  • 一文讀懂幼兒急疹
    (由「問藥師」團隊許書慧藥師供稿)
  • 十字勳章打造全新品類「萬能背包」,上班出差,一包搞定!
    作為延續傳統瑞士工藝且與時俱進,兼具創新的一個品牌,十字勳章在2019年推出了品牌的全新品類「萬能背包」! 萬能背包的靈感來源於瑞士軍刀,瑞士軍刀,又常稱為瑞士刀、萬用刀是瑞士軍方為士兵配備的工具刀而得名。
  • 一起來捉妖:背包問題得到解決?資源獲取也將變得非常簡單
    一起來捉妖這款遊戲出來也已經有一段時間了,就目前而言,遊戲中的一些設定也是比較不盡人意,受到了大家的一致吐槽,其中最為突出的應該就是關於遊戲中的背包問題了,大部分玩家應該都有遇到過背包空間不足的情況吧,一般背包不足,除了丟些東西之外,就是對背包進行擴容,而一次就要花掉不少的鑽石。