揹包問題

1、問題描述


 給定n種物品和一個揹包,物品i(1≤i≤n)的重量是wi,其價值爲vi,揹包的容量爲C。對每種物品只有兩種選擇:裝入揹包或者不裝入揹包。如何選擇裝入揹包的物品,使得裝入揹包中物品的總價值最大?ios

2、分析與求解


這是一個經典的動態規劃問題。容易證實,其知足最優子結構性質:即設(x1, x2, ..., xn)是該問題的一個最優解(其中xi=1表示放入物品i,xi=0表示不放入),則(x1, x2, ..., xk-1, xk+1, ..., xn)必定是原問題去除物品k後獲得的子問題的最優解。函數

2.1 0/1揹包問題

首先咱們看一下揹包問題的一個特例:0/1揹包問題。(例題見於:Openjudge-0/1揹包問題spa

在此問題中,每種物品只有一件。因而,對於第i件物品,只有兩種選擇:放入揹包或者不放入。最優解的遞推表達式:code

其中fk(y)表示揹包容量爲y且只能取前k種物品的條件下,能夠放入的物品的最大總價值。blog

爲了在求得最大總價值後,找到對應的最優解,還須要標記函數。令標記函數Ik(y)表示揹包容量爲y且只能取前k種物品的條件下,放入的物品的最大序號,則有ci

因而,咱們能夠寫出0/1揹包問題的代碼:get

『C++』it

#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 200
#define maxw 200

int n, C;

void TraceBack(int (*I)[maxn], int *w, int W) {
    int x[maxn] = {};
    int y = W, k = n;

    while (I[k][y] != 0) {
        while (I[k][y] == k) {
            y -= w[k];
            x[k]++;
        }
        k = I[k][y];
    }
    for (int i = 1; i <= n; i++) 
        printf("%d\n", x[i]);
    
    return;
}

int main()
{
    while (cin >> n >> C) {
        int w[maxn] = {}, v[maxn] = {};
        int F[maxn][maxw] = {};
        int I[maxn][maxw] = {};
        int W[maxn][maxn] = {};
        for (int k = 1; k <= n; k++) {
            cin >> w[k] >> v[k];
        }
        for (int k = 1; k <= n; k++) {
            for (int y = 0; y <= C; y++) {
                if (y >= w[k] && F[k - 1][y] < F[k - 1][y - w[k]] + v[k]) {
                    F[k][y] = F[k - 1][y - w[k]] + v[k];
                    W[k][y] = W[k - 1][y - w[k]] + w[k];
                    I[k][y] = k;
                }
                else {
                    F[k][y] = F[k - 1][y];
                    W[k][y] = W[k - 1][y];
                    I[k][y] = I[k - 1][y];
                }
            }
        }

        printf("%d\n", F[n][C]);

        TraceBack(I, w, W[n][C]);
    }

    //system("pause");
    return 0;
}

2.2 揹包問題

若同一種物品能夠放入多個,則標記函數同上,而只需將遞推方程改成以下便可:io

相關文章
相關標籤/搜索