home

Dynamic Programming

Table of Contents

DP

  • DP -> Enhanced Recursion
  • First do Recursion -> memoization (dp) -> top-down (dp)

How to identify a dp problem?

  • Choice: A problem contains some choices that I have to make.
  • Optimum: A problem asks for optimum solution (max. pairs, min. numbers, etc).

0/1 knapsack problems

Given a set of items, each with a weight and a value, determine which items to include in the collection so that the total weight is less than or equal to a given limit and the total value is as large as possible – Wikipedia

  • Fractional knapsack (greedy): We can put fractions of an item in the bag if the capacity left is less than the weight of the item.
  • 0/1 knapsack (dp): The whole item will be put (1) or none (0).
  • Unbounded knapsack: Copies of one item can be put multiple number of times to reach an optimal solution.

DP: Recursive Solution -> memoization (dp) -> top-down (dp)

Input:
weight[] = 1 3 4 5
value[]  = 1 4 5 7
W        = 7

Output: Max. value

practice link: gfg

Recursive approach:

zero_one_knapsack.png

#include <iostream>
#include <vector>

using std::vector;

auto knapsack(vector<int> &wt, vector<int> &val, int w, int n) {
    if (w == 0 || n == 0) return 0;

  if (wt[n - 1] <= w) {
    return std::max(val[n - 1] + knapsack(wt, val, w - wt[n - 1], n - 1),
                    knapsack(wt, val, w, n - 1));
  } else {
    return knapsack(wt, val, w, n - 1);
  }
}

int main() {
  vector<int> wt  = {1, 3, 4, 5};
  vector<int> val = {1, 4, 5, 7};
  int W = 7;

  auto res = knapsack(wt, val, W, val.size());

  std::cout << res;
}
9

Memoized Solution:

#include <iostream>
#include <vector>
#include <cstring>

using std::vector;

int cache[101][1001];

auto knapsack(vector<int> &wt, vector<int> &val, int w, int n) {
  if (w == 0 || n == 0) return 0;

  if (cache[n][w] != -1) {
    return cache[n][w];
    }

  if (wt[n - 1] <= w) {
    cache[n][w] = std::max(val[n- 1] + knapsack(wt, val, w - wt[n - 1], n - 1),
                           knapsack(wt, val, w, n - 1));

  } else {
    cache[n][w] = knapsack(wt, val, w, n - 1);
  }

  return cache[n][w];
}

int main() {
  vector<int> wt  = {1, 3, 4, 5};
  vector<int> val = {1, 4, 5, 7};
  int W = 7;

  memset(cache, -1, sizeof(cache));

  auto res = knapsack(wt, val, W, val.size());

  std::cout << res;
}
9

Top-down approach:

TODO: I don't understand this 😓

#include <iostream>
#include <vector>
#include <cstring>

using std::vector;

auto knapsack(vector<int> &wt, vector<int> &val, int w, int n) {
    int cache[n + 1][w + 1];
    // initialize matrix
    for(int i = 1; i < w + 1; ++i) cache[0][i] = 0;
    for(int i = 1; i < n + 1; ++i) cache[i][0] = 0;

    // choice diagram to code
    for(int i = 1; i < n+1; i++){
        for(int j=1; j < w+1; j++){
            //1. In case of choice
            if(wt[i-1] <= j){
                cache[i][j] = std::max(val[i-1] + cache[i-1][j-wt[i-1]], 0+cache[i-1][j]);
            }
            //2. No choice
            else if(wt[i-1] > j){
                cache[i][j] = 0+cache[i-1][j];
            }
        }
    }

    return cache[n][w];
}

int main() {
    vector<int> wt  = {1, 3, 4, 5};
    vector<int> val = {1, 4, 5, 7};
    int W = 7;

    auto res = knapsack(wt, val, W, val.size());

    std::cout << res;
}
9

TODO Subset sum

TODO Equal sum partition

TODO Count of subset sum

TODO Minimum subset sum difference

TODO Target sum

TODO Number of subset with given difference

Author: Siddhant Kumar