Knapsack

Fractional knapsack

greedy, sort items by value/wt and pick max ones

0/1 Knapsack - O(nw) time and O(nw) space variant

  • def: f(w) max value s.t. wt w
  • trans: for each item, for wt (rev) : f(w) = max{ self, f(w-wt) + val }

O(nw) time, O(w) space

printing items

use the 2d variation, dp(i,w) first i items, wt w

rem: 2d way needs you to copy dp(i-1) over to dp(i), this is the not take case

compare f(i,W) and f(i-1,W) note that this is not for weight exactly w but w. If same, you don’t need the ith item in your solution set ( note that this is one valid set )

0/1 KP - printing must and maybe set

This problem: https://atcoder.jp/contests/abc441/tasks/abc441_f

method 1: meet in the middle

use prefix of items and suffix of items to find “with i” and “without i” best values

make the 2d calc, once as items in initial order (pref(i,w)) and once with items in reverse order (suff(i,w))

without is easy, just skip i and connect prefix and suffix. without i = max{ for w : pref(i-1,w) + suff(i+1,W-w) }

with is similarly, with = val(i) + max{ for w: pref(i-1,w) + suff(i-1,W-w-wt(i)) }. basically you push in i and account for rest

must with is global max ( this is just pref(n,w) ), and without < global max maybe with is global max and without is global max never without = global max

This is O(nw) in time and mem

method 2: inverse dnc

visualise the opertaion done as “processing an invidual item on a dp array”. I do a “push” operation and it applies transitions to the dp array. Inverse dnc is similar, if you are at leaf, you want to reach a state where all but current item is “pushed”.

key idea is: shared processing and shared state so that segments get shared.

copy full dp array at each node

  • sharing: when at root and you go to left, you know all nodes in left subtree need right processed, this is done once.
  • copying: both left and right work with exclusive ranges, hence you need to copy

root 0 to n-1, left is 0 to mid, right is mid+1 to n-1.

trading time for memory improv. time is O(nw log n) and mem is O(w log n).

  • note: you can do 10^8 mem in contests, that works

this is the core code

auto f = [&](auto &&f, int l, int r, vector<int> &cur_dp) -> void {
    if (l == r) {
        int without = cur_dp[w];
 
        int with = -INF;
        if (wt[l] <= w) {
            with = cur_dp[w - wt[l]] + val[l];
        }
 
        if (with == best_val) {
            if (without < best_val) {
                ans[l] = 'A';
            } else {
                ans[l] = 'B';
            }
        }
        return;
    }
 
    // both sides now
    vector<int> ldp = cur_dp, rdp = cur_dp;
    int m = (l + r) / 2;
    fill_items(ldp, m + 1, r); // right side on left
    f(f, l, m, ldp);
 
    fill_items(rdp, l, m);
    f(f, m + 1, r, rdp);
};

unbounded knapsack

infinite uses of knapsack

trick is to iterate forward from wt(i) till W as this allows you to use “prev” state created via current item