package com.interview.algorithms.dp;
/**
* Created_By: zouzhile
* Date: 2/23/14
* Time: 5:02 PM
*
* Provide three different solutions for Boolean Knapsack
* 1. Recursive O(2^n)
* 2. DP Solution 1: define opt[n][w] = max profit of packing items 1..n with weight limit w
* scan the items, and only consider ith item put in or not.
* opt[i, j] = max( opt[i-1, j-Wi] + Vi (j >= Wi), opt[i-1, j] )
* 3. DP Solution 2: define optimal[S], the max profit could get when put S weight in bag
* scan the W, try to build opt[W] and solution[W][_]
* opt[S] = max(opt[S-Wi]+Vi. opt[S-1]) and filter the item if it already in the bag
*/
public class C12_1_BooleanKnapsack {
public static int getMaxValueByRecursion(int index, int W, int[] weights, int[] values) {
if(index < 0)
return 0;
if(weights[index] > W) {
return getMaxValueByRecursion(index - 1, W, weights, values);
} else {
return Math.max(getMaxValueByRecursion(index - 1, W, weights, values),
getMaxValueByRecursion(index - 1, W - weights[index], weights, values) + values[index]);
}
}
public static boolean[] getMaxValueByDPS2(int W, int[] weights, int[] values) {
int N = values.length;
// optimal[S], the max profit could get when put S weight in bag
// solution[S][], the solution of the max profit of S
int[] optimal = new int[W + 1];
boolean[][] solution = new boolean[W + 1][N];
for(int s = 1; s <= W; s++){
for(int j = 0; j < N; j++){
int left = s - weights[j];
//if jth item could put in, and optimal is larger and jth item haven't been put in before
if(left >= 0 && optimal[left] + values[j] > optimal[s] && !solution[left][j]) {
optimal[s] = optimal[s - weights[j]] + values[j];
copySolution(solution, N, left, s);
solution[s][j] = true;
}
}
if(s < W) { //if have next S
optimal[s+1] = optimal[s];
copySolution(solution, N, s, s+1);
}
}
return solution[W];
}
private static void copySolution(boolean[][] solution, int N, int from, int to){
for(int i = 0; i < N; i ++) {
solution[to][i] = solution[from][i];
}
}
//NOT A GOOD SOLUTION AS getMaxValueByDPS2
public static int getMaxValueByDPS1(int W, int[] weights, int[] values) {
int N = weights.length; // the number of item types
weights = shift(weights);
values = shift(values);
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w include item n?
int[][] opt = new int[N+1][W+1];
boolean[][] sol = new boolean[N+1][W+1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n-1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weights[n] <= w)
option2 = values[n] + opt[n-1][w-weights[n]];
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
return opt[N][W];
}
private static int[] shift(int[] array){
int[] result = new int[array.length + 1];
for(int i = 0; i < array.length; i++)
result[i+1] = array[i];
result[0] = 0;
return result;
}
}