knapsack_editorial

0/1 Knapsack

De bai

Cho NN vat pham, vat thu ii co trong luong w[i]w[i] va gia tri v[i]v[i]. Ban co mot ba lo voi suc chua toi da WW. Hay chon mot tap con cac vat pham sao cho tong trong luong khong vuot qua WW va tong gia tri la lon nhat.

Rang buoc: moi vat pham chi duoc chon hoac khong chon (0/1), khong duoc chia nho.

Input mau: N=4N = 4, W=5W = 5, trong luong w=[2,3,4,5]w = [2, 3, 4, 5], gia tri v=[3,4,5,6]v = [3, 4, 5, 6].

Cong thuc truy hoi

Goi dp[i][j]dp[i][j] la gia tri lon nhat khi xet ii vat pham dau tien voi suc chua jj. Ta co cong thuc truy hoi:

dp[i][j]=max(dp[i1][j],  dp[i1][jw[i]]+v[i])dp[i][j] = \max\bigl(dp[i-1][j],\; dp[i-1][j - w[i]] + v[i]\bigr)

Truong hop co so: dp[0][j]=0dp[0][j] = 0 voi moi jj (khong chon vat nao thi gia tri bang 00).

Dieu kien: chi co the lay vat ii khi jw[i]j \geq w[i]. Neu j<w[i]j < w[i] thi dp[i][j]=dp[i1][j]dp[i][j] = dp[i-1][j].

So do bang DP – trang thai ban dau

000000dp[i][j]

Hang i=0i = 0 tuong ung voi viec khong chon vat nao. Moi o dp[0][j]=0dp[0][j] = 0. Cac hang tiep theo se duoc dien bang cach ap dung cong thuc truy hoi, xet tung vat pham mot tu trai sang phai.

Giai thich trang thai DP

Moi o dp[i][j]dp[i][j] dai dien cho bai toan con: gia tri lon nhat co the dat duoc khi chi xet ii vat pham dau va suc chua la jj. Tai moi o, ta co hai lua chon:

Gia tri lon hon trong hai lua chon se duoc ghi vao dp[i][j]dp[i][j].

Qua trinh dien bang DP

Step 1 / 13

Truy vet loi giai

Sau khi dien xong bang DP, dap an nam o dp[N][W]dp[N][W]. De biet nhung vat nao duoc chon, ta truy vet tu dp[N][W]dp[N][W] nguoc ve dp[0][0]dp[0][0]:

  1. Bat dau tai i=Ni = N, j=Wj = W.
  2. Neu dp[i][j]dp[i1][j]dp[i][j] \neq dp[i-1][j], thi vat ii duoc chon. Giam jj di w[i]w[i], giam ii di 11.
  3. Neu dp[i][j]=dp[i1][j]dp[i][j] = dp[i-1][j], thi vat ii khong duoc chon. Chi giam ii di 11.
  4. Lap lai cho den khi i=0i = 0.

Trong vi du tren: dp[4][5]=7=dp[3][5]dp[4][5] = 7 = dp[3][5] (khong lay vat 44), dp[3][5]=7=dp[2][5]dp[3][5] = 7 = dp[2][5] (khong lay vat 33), dp[2][5]=7dp[1][5]=3dp[2][5] = 7 \neq dp[1][5] = 3 (lay vat 22, jj giam tu 55 ve 22), dp[1][2]=3dp[0][2]=0dp[1][2] = 3 \neq dp[0][2] = 0 (lay vat 11, jj giam tu 22 ve 00). Vay tap vat duoc chon la {1,2}\{1, 2\} voi tong gia tri 3+4=73 + 4 = 7.

Cai dat

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, W;
    cin >> n >> W;
    vector<int> w(n + 1), v(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> w[i] >> v[i];

    // dp[i][j] = max value using items 1..i with capacity j
    vector<vector<int>> dp(n + 1, vector<int>(W + 1, 0));

    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= W; j++) {
            dp[i][j] = dp[i - 1][j]; // skip item i
            if (j >= w[i])
                dp[i][j] = max(dp[i][j], dp[i - 1][j - w[i]] + v[i]);
        }
    }

    cout << dp[n][W] << "\n";

    // Backtrack to find chosen items
    vector<int> chosen;
    for (int i = n, j = W; i >= 1; i--) {
        if (dp[i][j] != dp[i - 1][j]) {
            chosen.push_back(i);
            j -= w[i];
        }
    }

    reverse(chosen.begin(), chosen.end());
    for (int x : chosen)
        cout << x << " ";
    cout << "\n";

    return 0;
}

Do phuc tap: O(NW)O(N \cdot W) thoi gian va bo nho. Co the toi uu bo nho xuong O(W)O(W) bang cach chi giu mot hang DP va duyet jj giam dan.