package com.interview.algorithms.general;
/**
* Created with IntelliJ IDEA.
* User: stefanie
* Date: 14-2-19
* Time: 上午8:43
* To change this template use File | Settings | File Templates.
*
* Given a capacity value N, and a set of different Item types with values v1, v2, ...,vn
* 1) Existence Check: check whether N can be filled with a certain combination of items
* 2) All Combinations: get all the combinations of items that fills N
* 3) Minimum Combination: get the minimum number of items that fills N
*/
public class C1_32_CapacityAndItems {
public boolean check(int N, int[] items) {
return check(N, 0, items);
}
public boolean check(int N, int currentSum, int[] items) {
if(currentSum > N)
return false;
if(currentSum == N)
return true;
for(int i = 0; i < items.length; i ++) {
if(this.check(N, currentSum + items[i], items))
return true;
}
return false;
}
class Status {
int sum = 0;
int[] itemsCount;
int code = -1;
}
/**
* If N can buy the items with the given items, get the amount of each item
* @param N
* @param items
* @return
*/
public void getAllCombinations(int N, int[] items) {
Status status = new Status();
status.itemsCount = new int[items.length];
getAllCombinations(N, items, status, 0);
}
public void getAllCombinations(int N, int[] items, Status status, int itemType) {
if(status.sum > N){
status.code = 1;
return;
}
if(status.sum == N) {
printCombination(items, status.itemsCount, status.sum);
status.code = 0;
return;
}
// given current itemsCount[type]
// the for loop try with more items[type] or the types after the given "type"
// i.e. look down or right.
for(int i = itemType; i < items.length; i ++) {
// put in item[i]
status.itemsCount[i] += 1;
status.sum += items[i];
this.getAllCombinations(N, items, status, i);
if(status.code >= 0) {
// when the last itm make the sum equal or bigger than N,
// move out the last item to try other items
status.sum -= items[i];
status.itemsCount[i] -= 1; // take out item[i]
}
}
// try with 1 less items[type] and then look at right side by recursion after line 72
status.itemsCount[itemType] --;
status.sum -= items[itemType];
status.code = -1;
}
private void printCombination(int[] items, int[] itemsCount, int sum) {
for(int i = 0; i < items.length; i ++)
System.out.print("\t" + items[i] + ":" + itemsCount[i]);
System.out.print("\tsum=" + sum);
System.out.println();
}
private int[] sortInDescendingOrder(int[] items) {
// bubble sort, since the amount of items is very trivial
for(int i = 0; i < items.length - 1; i++)
for(int j = i + 1; j < items.length; j ++) {
if(items[j] > items[i]){
int tmp = items[i];
items[i] = items[j];
items[j] = tmp;
}
}
return items;
}
/**
* Sort the items by value in descending order
* The minimum combination is the first combination that fills N.
* @param N
* @param items
*/
public void getMinimumCombination(int N, int[] items) {
items = this.sortInDescendingOrder(items);
Status status = new Status();
status.itemsCount = new int[items.length];
getMinimumCombination(N, items, status, 0);
}
private void getMinimumCombination(int N, int[] items, Status status, int itemType) {
if(status.sum > N) {
status.code = 1;
return;
}
if(status.sum == N){
status.code = 0;
printCombination(items, status.itemsCount, status.sum);
System.exit(0);
}
for(int i = itemType; i < items.length; i ++) {
status.itemsCount[i] += 1;
status.sum += items[i];
this.getMinimumCombination(N, items, status, i);
if(status.code >= 0){
status.sum -= items[i];
status.itemsCount[i] --;
}
}
status.itemsCount[itemType] --;
status.sum -= items[itemType];
status.code = -1;
}
public static void main(String[] args) {
C1_32_CapacityAndItems checker = new C1_32_CapacityAndItems();
int N = 42;
int[] items = new int[]{6, 9, 20};
String itemString = "";
for(int item : items)
itemString += item + " ";
System.out.println("N = " + N + ", items = " + itemString);
System.out.println("Combination Exists? : " + checker.check(N, items));
System.out.println("All Combinations: ");
checker.getAllCombinations(N, items);
System.out.println("Minimum Combination");
checker.getMinimumCombination(N, items);
}
}