動態規划(一)——0-1背包問題


動態規划(1)——0-1背包問題

1 題目描述

  對於一組不同重量、不可分割的物品,我們需要選擇一些裝入背包,在滿足背包最大重量限制的前提下,背包中物品總重量的最大值是多少呢?

2 輸入

  第一行是物品的個數n(1≤n≤100000),背包容量w(1≤w≤1000000);
  第二行是n個物品的重量。

3 輸出

  輸出最大值

4 樣例輸入

5 9
2 2 4 6 3

5 樣例輸出

9

6 求解思路

  把問題分解為多個階段,每個階段對應一個決策。我們記錄每一個階段可達的狀態集合(去掉重復的),然后通過當前階段的狀態集合,來推導下一個階段的狀態集合,動態地往前推進。這也是動態規划這個名字的由來,你可以自己體會一下,是不是還挺形象的?

7 C++版本代碼如下

#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;

#define MAXNUM 100010

int dpFirst(int weight[], int n, int weightLimit){
    bool states[n][weightLimit + 1];
    memset(states, false, sizeof(states));
    // 第一行單獨處理
    states[0][0] = true;
    if(weight[0] <= weightLimit)
        states[0][weight[0]] = true;

    // 動態規划狀態轉移
    for(int i = 1; i < n; i++){
        for(int j = 0; j < weightLimit + 1; j++)
            if(states[i - 1][j]){
                // 不裝
                states[i][j + 0] = true;
                // 裝
                states[i][j + weight[i]] = true;
            }
    }
    // 找出最后一個狀態下的背包值
    int maxPower = 0;
    for(int i = 0; i <= weightLimit; i++)
        if(states[n - 1][i])
            maxPower = i;
    return maxPower;
}

int main()
{
    int weight[5] = {2,2,4,6,3};
    cout<<dpFirst(weight, 5, 9)<<endl;;
    return 0;
}

  因為只需要判斷最后一個狀態下的背包容量,所以可以使用一個數組states[weightLimit]即可解決問題,代碼可優化空間復雜度如下:
  其中注意上一個二維數組的方法中數組weight的訪問可能越界,所以修改為j <= weightLimit - weight[i + 1]保證了數組weight不會越界,表示“當前狀態”能裝下的。

int dpFirst(int weight[], int n, int weightLimit){
    bool states[weightLimit + 1];
    memset(states, false, sizeof(states));
    // 單獨處理第一個狀態
    states[0] = true;
    if(weight[0] <= weightLimit)
        states[weight[0]] = true;

    // 動態規划狀態轉移用一個數組解決
    for(int i = 1; i < n; i++){
        // 可以直接寫成weightLimit - weight[i],而不是weightLimit
        // 這樣可以少幾個判斷,並且保證了數組weight不會越界
        for(int j = 0; j <= weightLimit - weight[i]; j++){
            if(states[j])
                // 裝
                states[j+ weight[i]] = true;
        }
    }

    // 找出最后一個狀態下的背包值
    for(int i = weightLimit; i >= 0; i--)
        if(states[i])
            return i;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM