0-1揹包問題

1.問題描述

有n個物品,第i個物品的體積和價值分別爲w[i]、v[i](1<= i <=n),現有一個容量爲c的揹包,將這些物品選擇裝入該揹包,如何選擇使得包裏的物品價值總和最大。

2.問題分析

定義函數f[i][w]表示從前i件物品中選擇放入容量爲w的揹包能裝下的物品最大價值,我們所要求的就是f[n][c]。以n爲例,有兩種情況:

a. 如果w[n]>c,那麼n就不能選中,即f[n][c] = f[n-1][c]

b. 如果w[n] <= c, 那麼n有可能選中也可能沒有選中,依據就是判斷選中和不選中的結果哪個大酒根據那一個,即比較f[n-1][c-w[n]]+v[n]和f[n-1][c]

3.編寫代碼

在解決該問題時因爲每一個f都依賴上一個結果,所以需要從最小的f開始向上計算,得到結果,易得f[0][i] f[i][0]都是0,我們需要從0開始計算出所有f[][]

//i表示從前i項選擇,j表示容量
for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= c; j++) {
            if (w[i] > j) {
                f[i][j] = f[i - 1][j];
            } else {
                f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
            }
        }
    }

完整代碼如下

#include <iostream>
#include <cmath>

using namespace std;

int knapsack(int n, int c, int v[], int w[]) {
    int f[1001][1001] = {0};
    
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= c; j++) {
            if (w[i] > j) {
                f[i][j] = f[i - 1][j];
            } else {
                f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + v[i]);
            }
        }
    }
    return f[n][c];
}

int main () {
    
    int n, v[1001];
    int c, w[1001];
    
    while (cin >> n >> c) {
        for (int i = 1; i <= n; i++) {
            cin >> w[i] >> v[i];
        }
        
        cout << knapsack(n, c, v, w) << endl;
    }
    
    return 0;
}

如果想得到選擇的具體情況可以通過f[i][c]-f[i-1][c]的值判斷,如果f[i][c]>f[i-1][c],那麼就是選取了第i個,接下來就要判斷f[i - 1][c - w[i]] 和f[i - 2][c - w[i]],注意i從大到小判斷,遇到被選中的,加下來的判斷就要減去這個重量


int w = totalWeight;
for (int i = n; i != 0; i--) {
       if (f[i][w] > f[i - 1][w]) {
            cout << i << " ";
	    w -= w[i];
        }
    }




發佈了40 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章