UPDATE: I have realized the problem below is not possible to answer in its current form because of the large amount of data involved(15k+ items). I just found out, the
This uses dynamic programming to solve the same problem you gave in the example. It's been updated to deal with duplicate values by keeping track of the value's index rather than its value, and to correct a bug which omitted some solutions.
public class TurboAdder {
private static final int[] data = new int[] { 5, 10, 20, 25, 40, 50 };
private static class Node {
public final int index;
public final int count;
public final Node prevInList;
public final int prevSum;
public Node(int index, int count, Node prevInList, int prevSum) {
this.index = index;
this.count = count;
this.prevInList = prevInList;
this.prevSum = prevSum;
}
}
private static int target = 100;
private static Node sums[] = new Node[target+1];
// Only for use by printString.
private static boolean forbiddenValues[] = new boolean[data.length];
public static void printString(String prev, Node n) {
if (n == null) {
System.out.println(prev);
} else {
while (n != null) {
int idx = n.index;
// We prevent recursion on a value already seen.
if (!forbiddenValues[idx]) {
forbiddenValues[idx] = true;
printString((prev == null ? "" : (prev+" + "))+data[idx]+"*"+n.count, sums[n.prevSum]);
forbiddenValues[idx] = false;
}
n = n.prevInList;
}
}
}
public static void main(String[] args) {
for (int i = 0; i < data.length; i++) {
int value = data[i];
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
for (int newsum = sum+1; newsum <= target; newsum++) {
if (sums[newsum - sum] != null) {
sums[newsum] = new Node(i, count, sums[newsum], newsum - sum);
}
}
}
for (int count = 1, sum = value; count <= 100 && sum <= target; count++, sum += value) {
sums[sum] = new Node(i, count, sums[sum], 0);
}
}
printString(null, sums[target]);
}
}