One way to think about this problem is to count in a different base system. You use the number of unique coins as the base. So for your example of 10, 30, and 50, the base would be 3.
Now you need numbers in that base system that have the correct number of digits, which is 4 for your example. Since each digit can be only one of 3 values in base 3 (0, 1, or 2), the total number of possibilites is 3 raised to the power of 4, or 81.
Thus we can count from 0 to 80 in decimal, and convert that decimal number to a four digit base 3 number using stacked repeated division.
Here's what those four digit base 3 numbers would look like:
0 in base 3: [0, 0, 0, 0]
1 in base 3: [0, 0, 0, 1]
2 in base 3: [0, 0, 0, 2]
3 in base 3: [0, 0, 1, 0]
4 in base 3: [0, 0, 1, 1]
5 in base 3: [0, 0, 1, 2]
6 in base 3: [0, 0, 2, 0]
7 in base 3: [0, 0, 2, 1]
8 in base 3: [0, 0, 2, 2]
9 in base 3: [0, 1, 0, 0]
10 in base 3: [0, 1, 0, 1]
11 in base 3: [0, 1, 0, 2]
12 in base 3: [0, 1, 1, 0]
13 in base 3: [0, 1, 1, 1]
14 in base 3: [0, 1, 1, 2]
15 in base 3: [0, 1, 2, 0]
16 in base 3: [0, 1, 2, 1]
17 in base 3: [0, 1, 2, 2]
18 in base 3: [0, 2, 0, 0]
19 in base 3: [0, 2, 0, 1]
20 in base 3: [0, 2, 0, 2]
21 in base 3: [0, 2, 1, 0]
22 in base 3: [0, 2, 1, 1]
23 in base 3: [0, 2, 1, 2]
24 in base 3: [0, 2, 2, 0]
25 in base 3: [0, 2, 2, 1]
26 in base 3: [0, 2, 2, 2]
27 in base 3: [1, 0, 0, 0]
28 in base 3: [1, 0, 0, 1]
29 in base 3: [1, 0, 0, 2]
30 in base 3: [1, 0, 1, 0]
31 in base 3: [1, 0, 1, 1]
32 in base 3: [1, 0, 1, 2]
33 in base 3: [1, 0, 2, 0]
34 in base 3: [1, 0, 2, 1]
35 in base 3: [1, 0, 2, 2]
36 in base 3: [1, 1, 0, 0]
37 in base 3: [1, 1, 0, 1]
38 in base 3: [1, 1, 0, 2]
39 in base 3: [1, 1, 1, 0]
40 in base 3: [1, 1, 1, 1]
41 in base 3: [1, 1, 1, 2]
42 in base 3: [1, 1, 2, 0]
43 in base 3: [1, 1, 2, 1]
44 in base 3: [1, 1, 2, 2]
45 in base 3: [1, 2, 0, 0]
46 in base 3: [1, 2, 0, 1]
47 in base 3: [1, 2, 0, 2]
48 in base 3: [1, 2, 1, 0]
49 in base 3: [1, 2, 1, 1]
50 in base 3: [1, 2, 1, 2]
51 in base 3: [1, 2, 2, 0]
52 in base 3: [1, 2, 2, 1]
53 in base 3: [1, 2, 2, 2]
54 in base 3: [2, 0, 0, 0]
55 in base 3: [2, 0, 0, 1]
56 in base 3: [2, 0, 0, 2]
57 in base 3: [2, 0, 1, 0]
58 in base 3: [2, 0, 1, 1]
59 in base 3: [2, 0, 1, 2]
60 in base 3: [2, 0, 2, 0]
61 in base 3: [2, 0, 2, 1]
62 in base 3: [2, 0, 2, 2]
63 in base 3: [2, 1, 0, 0]
64 in base 3: [2, 1, 0, 1]
65 in base 3: [2, 1, 0, 2]
66 in base 3: [2, 1, 1, 0]
67 in base 3: [2, 1, 1, 1]
68 in base 3: [2, 1, 1, 2]
69 in base 3: [2, 1, 2, 0]
70 in base 3: [2, 1, 2, 1]
71 in base 3: [2, 1, 2, 2]
72 in base 3: [2, 2, 0, 0]
73 in base 3: [2, 2, 0, 1]
74 in base 3: [2, 2, 0, 2]
75 in base 3: [2, 2, 1, 0]
76 in base 3: [2, 2, 1, 1]
77 in base 3: [2, 2, 1, 2]
78 in base 3: [2, 2, 2, 0]
79 in base 3: [2, 2, 2, 1]
80 in base 3: [2, 2, 2, 2]
The integer in each resulting array (the base 3 number) represents which coin from the original coin values should go in that spot (0 = 10, 1 = 30, 2 = 50).
For example, the number 61 in decimal is 2021 in base 3:
61 in base 3: [2, 0, 2, 1]
The resulting coin combination for that number would be:
50, 10, 50, 30
Here's the code that generated the list of base 3 numbers above:
import java.util.Arrays;
class Main {
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
System.out.println(d + " in base " + base + ": " + Arrays.toString(combinations[d]));
}
}
public static int[] convertToBase(int decimalNumber, int base, int numDigits) {
int[] digits = new int[numDigits];
int index = digits.length - 1;
int quotient = decimalNumber;
while (quotient > 0) {
digits[index] = quotient % base;
index--;
quotient = quotient / base;
}
return digits;
}
}
Now that you have all possible combinations of four coins, you need to add up the values from each combo and see if they add up to 80.
Here's a new main() to do just that:
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
Producing the following output:
Coins: 10 10 10 50 = 80
Coins: 10 10 30 30 = 80
Coins: 10 10 50 10 = 80
Coins: 10 30 10 30 = 80
Coins: 10 30 30 10 = 80
Coins: 10 50 10 10 = 80
Coins: 30 10 10 30 = 80
Coins: 30 10 30 10 = 80
Coins: 30 30 10 10 = 80
Coins: 50 10 10 10 = 80
Notice that there are repeats because the same combination of coin denominations could be put into different positions of the four slots.
If you want to get rid of duplicates, you could SORT the resulting combos and add them to a Hashmap if they don't already exist (add import java.util.HashMap;
):
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
HashMap<String, String> uniqueCombos = new HashMap<String, String>();
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
Arrays.sort(combinations[d]);
String key = Arrays.toString(combinations[d]);
if (!uniqueCombos.containsKey(key)) {
uniqueCombos.put(key, combo);
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
}
Now we only get the two unique combinations in our output:
Coins: 10 10 10 50 = 80
Coins: 10 10 30 30 = 80
Here is the final version of the entire program:
import java.util.Arrays;
import java.util.HashMap;
class Main {
public static void main(String[] args) {
int sum = 80;
int numCoins = 4;
int[] coins = new int[]{10, 30, 50};
int base = coins.length;
int combos = (int)Math.pow(base, numCoins);
int[][] combinations = new int[combos][];
HashMap<String, String> uniqueCombos = new HashMap<String, String>();
for(int d=0; d<combos; d++) {
combinations[d] = convertToBase(d, base, numCoins);
String combo = "";
int curSum = 0;
for(int coinChoice : combinations[d]) {
combo = combo + coins[coinChoice] + " ";
curSum = curSum + coins[coinChoice];
}
if (curSum == sum) {
Arrays.sort(combinations[d]);
String key = Arrays.toString(combinations[d]);
if (!uniqueCombos.containsKey(key)) {
uniqueCombos.put(key, combo);
System.out.println("Coins: " + combo + " = " + curSum);
}
}
}
}
public static int[] convertToBase(int decimalNumber, int base, int numDigits) {
int[] digits = new int[numDigits];
int index = digits.length - 1;
int quotient = decimalNumber;
while (quotient > 0) {
digits[index] = quotient % base;
index--;
quotient = quotient / base;
}
return digits;
}
}