package com.interview.dynamic; import java.util.HashMap; import java.util.Map; /** * Date 04/04/2014 * @author Tushar Roy * * 0/1 Knapsack Problem - Given items of certain weights/values and maximum allowed weight * how to pick items to pick items from this set to maximize sum of value of items such that * sum of weights is less than or equal to maximum allowed weight. * * Time complexity - O(W*total items) * * Youtube link * Topdown DP - https://youtu.be/149WSzQ4E1g * Bottomup DP - https://youtu.be/8LusJS5-AGo * * References - * http://www.geeksforgeeks.org/dynamic-programming-set-10-0-1-knapsack-problem/ * https://en.wikipedia.org/wiki/Knapsack_problem */ public class Knapsack01 { /** * Solves 0/1 knapsack in bottom up dynamic programming */ public int bottomUpDP(int val[], int wt[], int W){ int K[][] = new int[val.length+1][W+1]; for(int i=0; i <= val.length; i++){ for(int j=0; j <= W; j++){ if(i == 0 || j == 0){ K[i][j] = 0; continue; } if(j - wt[i-1] >= 0){ K[i][j] = Math.max(K[i-1][j], K[i-1][j-wt[i-1]] + val[i-1]); }else{ K[i][j] = K[i-1][j]; } } } return K[val.length][W]; } /** * Key for memoization */ class Index { int remainingWeight; int remainingItems; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Index index = (Index) o; if (remainingWeight != index.remainingWeight) return false; return remainingItems == index.remainingItems; } @Override public int hashCode() { int result = remainingWeight; result = 31 * result + remainingItems; return result; } } /** * Solves 0/1 knapsack in top down DP */ public int topDownRecursive(int values[], int weights[], int W) { //map of key(remainingWeight, remainingCount) to maximumValue they can get. Map<Index, Integer> map = new HashMap<>(); return topDownRecursiveUtil(values, weights, W, values.length, 0, map); } public int topDownRecursiveUtil(int values[], int weights[], int remainingWeight, int totalItems, int currentItem, Map<Index, Integer> map) { //if currentItem exceeds total item count or remainingWeight is less than 0 then //just return with 0; if(currentItem >= totalItems || remainingWeight <= 0) { return 0; } //fom a key based on remainingWeight and remainingCount Index key = new Index(); key.remainingItems = totalItems - currentItem -1; key.remainingWeight = remainingWeight; //see if key exists in map. If so then return the maximumValue for key stored in map. if(map.containsKey(key)) { return map.get(key); } int maxValue; //if weight of item is more than remainingWeight then try next item by skipping current item if(remainingWeight < weights[currentItem]) { maxValue = topDownRecursiveUtil(values, weights, remainingWeight, totalItems, currentItem + 1, map); } else { //try to get maximumValue of either by picking the currentItem or not picking currentItem maxValue = Math.max(values[currentItem] + topDownRecursiveUtil(values, weights, remainingWeight - weights[currentItem], totalItems, currentItem + 1, map), topDownRecursiveUtil(values, weights, remainingWeight, totalItems, currentItem + 1, map)); } //memoize the key with maxValue found to avoid recalculation map.put(key, maxValue); return maxValue; } public static void main(String args[]){ Knapsack01 k = new Knapsack01(); int val[] = {22, 20, 15, 30, 24, 54, 21, 32, 18, 25}; int wt[] = {4, 2, 3, 5, 5, 6, 9, 7, 8, 10}; int r = k.bottomUpDP(val, wt, 30); int r1 = k.topDownRecursive(val, wt, 30); System.out.println(r); System.out.println(r1); } }