I would make one suggestion about the design of the algorithm itself (which is how I interpreted the intent of your original question). Here is a fragment of the solution I wrote:
....
private void findAndReportSolutions(
int target, // goal to be achieved
int balance, // amount of goal remaining
int index // menu item to try next
) {
++calls;
if (balance == 0) {
reportSolution(target);
return; // no addition to perfect order is possible
}
if (index == items.length) {
++falls;
return; // ran out of menu items without finding solution
}
final int price = items[index].price;
if (balance < price) {
return; // all remaining items cost too much
}
int maxCount = balance / price; // max uses for this item
for (int n = maxCount; 0 <= n; --n) { // loop for this item, recur for others
++loops;
counts[index] = n;
findAndReportSolutions(
target, balance - n * price, index + 1
);
}
}
public void reportSolutionsFor(int target) {
counts = new int[items.length];
calls = loops = falls = 0;
findAndReportSolutions(target, target, 0);
ps.printf("%d calls, %d loops, %d falls%n", calls, loops, falls);
}
public static void main(String[] args) {
MenuItem[] items = {
new MenuItem("mixed fruit", 215),
new MenuItem("french fries", 275),
new MenuItem("side salad", 335),
new MenuItem("hot wings", 355),
new MenuItem("mozzarella sticks", 420),
new MenuItem("sampler plate", 580),
};
Solver solver = new Solver(items);
solver.reportSolutionsFor(1505);
}
...
(Note that the constructor does sort the menu items by increasing price, to enable the constant-time early termination when the remaining balance is smaller than any remaining menu item.)
The output for a sample run is:
7 mixed fruit (1505) = 1505
1 mixed fruit (215) + 2 hot wings (710) + 1 sampler plate (580) = 1505
348 calls, 347 loops, 79 falls
The design suggestion I want to highlight is that in the above code, each nested (recursive) call of findAndReportSolution(...)
deals with the quantity of exactly one menu item, identified by the index
argument. In other words, the recursive nesting parallels the behavior of an in-line set of nested loops; the outermost counts possible uses of the first menu item, the next in counts the uses of the second menu item, etc. (Except, of course, the use of recursion liberates the code from dependence on a specific number of menu items!)
I suggest that this makes it easier to design the code, and easier to understand what each invocation is doing (accounting for all possible uses of a specific item, delegating the remainder of the menu to subordinate calls). It also avoids the combinatorial explosion of producing all arrangements of a multiple-item solution (as in the second line of the above output, which only occurs once, instead of repeatedly with different orderings of the items).
I try to maximize the "obviousness" of the code, rather than trying to minimize the number of calls of some specific method. For example, the above design lets a delegated call determine if a solution has been reached, rather than wrapping that check around the point of the call, which would reduce the number of calls at the expense of cluttering up the code.