Java Algorithm to solve vendor machine 'change giving' problem - java

As a graduate I went for an interview for a java development role and was doing pretty well in the technical examinations until i came up against this question.
If i was setting up a vending machine which (for simplicity) returned £2 change. How would i produce an implemtation that would list all the possible combinations of £2.
For e.g £1 + £1 , £1 + 50p + 50p, 50p + 50p + 50p + 50p and so on..
How could i list all the different combinations of £2.00 change possible by the vending machine.
I began to write something and this is what ive came up with so far.
Its almost working except can someone help me find out why its not expanding fully. A second pair of eyes will be grateful. And also any ways it can be optimised.
Thanks guys.
private static void printCoins(int[] tempArray) {
for (int i = 0; i < tempArray.length - 1; i++){
// to stop my array from printing out any non-denominator coins e.g
if (tempArray[i] > 0){
System.out.print(tempArray[i] + ": ");
}
System.out.println("\n");
}
}
public static void vendingMachine() {
int[] denominations = {200,100, 50, 20, 10, 5, 2, 1};
int[] tempArray = new int[50]; //combination of coins made
int total = 200;
int coinCombiIndex = 0, denomCoinIndex = 0;
// whilst all denominations havent been visited
while (denomCoinIndex < denominations.length)
// if i have the correct change
if (total - denominations[denomCoinIndex] == 0){
tempArray[coinCombiIndex] = denominations[denomCoinIndex];
denomCoinIndex++; //increment so that next iteration starts with lower denom
printCoins(tempArray); // return coins
}
// checks to see whether new total minus coin (denominator) is still >= 0
else if (total - denominations[denomCoinIndex] >= 0) {
// if so SUBTRACT from total and ADD coin to coin-combination-array
total = total - denominations[denomCoinIndex];
tempArray[coinCombiIndex] = denominations[denomCoinIndex];
coinCombiIndex++;
}
else {
denomCoinIndex++;
}
// printCoins(tempArray);
}
my output
200:
100: 100:
100: 50: 50:
100: 50: 20: 20: 10:
100: 50: 20: 20: 5: 5:
100: 50: 20: 20: 5: 2: 2: 1:

To answer your second question:
Try with only {20,10} you will see that your program is really not right .
You tried to transform my recurence into a loop, and I guess it's the best solution. But it's very difficult to do that in one loop (you're missing a lot of possibilities).
You can try to reinialise the while loop with different constraint at each step for example adding a new while loop around your loop like this one
while (i<denominations.length){
total=200;
denomCoinIndex=i;
tempArray = new int[1000];
i++;
but it's still not enough ... so you will need to add some loop again until you treat all the cases.
I don't think your approach with a while loop is the good one here.
The easiest way would be to use for loop like this to treat all the possible solutions (from the similar question to your question):
int total = 200;
System.out. printf("quarter\tdime\tnickle\tpenny\tto make %d\n", total);
int combos = 0;
for (int q = 0; q <= total / 25; q++)
{
int total_less_q = total - q * 25;
for (int d = 0; d <= total_less_q / 10; d++)
{
int total_less_q_d = total_less_q - d * 10;
for (int n = 0; n <= total_less_q_d / 5; n++)
{
int p = total_less_q_d - n * 5;
System.out.printf("%d\t%d\t%d\t%d\n", q, d, n, p);
combos++;
}
}
}
System.out.printf("%d combinations\n", combos);
Hope it helps

Probably get started on looking at Dynamic programming. However you could any approach problem for that matter trivially. How would you do that manually ??. Jot down the steps. Convert it into an algorithm yourself. Probably studying Permutations & Combinations would help for better understanding of the problem you have stated.
Hope it helps.

Let say your possible coins are x1 ...xn :
if you're asked to print all the possiblities for $2 then you could print recursively all the possibilities for :
2-x1
2-x2
..
2-xn
Yoou will eventually get all the solutions
You can initialise this recursive process with amount-xi = 0 then print

Reframe the problem as follows: Given a standard (modern) car odometer that registers 6 digits with no fractions, find all possible values where the sum of the digits is some value, say 15. If you can solve that, you can solve the given problem.

Algorithm F on (in-text) page 7 is exactly what you're looking for. :)
http://www-cs-staff.stanford.edu/~uno/fasc3a.ps.gz

public class VendeningMachine
{
public static final int[] coins = {1, 5, 10, 25};
public static final int[] coinMax = {200, 40, 20, 8};
public static final int[] coinsString = { "Penny", "Nickle", "Dime", "Quarter"};
public static void main(String[] args)
{
}
public static void vendingMachine()
{
for ( int a = 0; a <= coinMax[0]; a++ ) {
for ( int b = 0; b <= coinMax[1]; b++ ) {
for ( int c = 0; c < coinMax[2]; c++ ) {
for ( int d = 0; d < coinMax[3]; d++ ) {
checkCoins(a, b, c, d);
}
}
}
}
}
public static void checkCoins(int penny, int nickle, int dime, int quarter)
{
int total = coins[0] * penny + coins[1] * nickle + coins[2] * dime + coins[3] * quarter;
if ( total == 200 )
printCoins(penny, nickle, dime, quarter);
}
public static void printCoins(int penny, int nickle, int dime, int quarter)
{
System.out.println("Penney : " + penny + " Nickle: " + nickle + " Dime: " + dime + " Quarter: " + quarter);
}
}enter code here

Related

Guessing Game logic (binary search)

Working on a problem in which I take a user's input (1-10) and guess what number they are thinking of using binary search, and update the range dependent on their answer (e.g. if it is greater than 5, I update the lowerLimit to 6) but am having trouble with the logic.
I use the middle cell as reference by adding 1 to the middle cell when they say it is greater than it, but I believe this is where I get confused. I can't figure out how to intertwine my if/else statement to update the number correctly.
Main method:
public class Main {
public static void main(String[] args) {
// test your program here
GuessingGame game = new GuessingGame();
game.play(1,10);
}
}
GuessingGame method (play method is the one I'm working with):
import java.util.Scanner;
public class GuessingGame {
private Scanner reader;
public GuessingGame() {
// use only this scanner, othervise the tests do not work
this.reader = new Scanner(System.in);
}
public void play(int LL, int UL) {
instructions(LL, UL);
int limit = howManyTimesHalvable(UL - LL);
int finalNumber = 0;
int midPoint = average(LL, UL);
int avgLL;
int avgUL;
for(int i = 0; i < limit; i++){
if(isGreaterThan(midPoint)){
midPoint++;
LL = midPoint;
midPoint = average(UL,LL);
finalNumber = LL;
}else{
midPoint--;
UL = midPoint;
midPoint = average(UL,LL);
finalNumber = LL;
}
if(UL == LL){
break;
}
}
System.out.println("Your number is : " + finalNumber);
}
public boolean isGreaterThan(int value){
System.out.println("Is your number greater than " + value + "?");
return reader.nextLine().equals("y");
}
public int average(int firstNumber, int secondNumber){
int total = firstNumber + secondNumber ;
return total / 2;
}
public void instructions(int lowerLimit, int upperLimit) {
int maxQuestions = howManyTimesHalvable(upperLimit - lowerLimit);
System.out.println("Think of a number between " + lowerLimit + "..." + upperLimit + ".");
System.out.println("I promise you that I can guess the number you are thinking with " + maxQuestions + " questions.");
System.out.println("");
System.out.println("Next I'll present you a series of questions. Answer them honestly.");
System.out.println("");
}
// a helper method:
public static int howManyTimesHalvable(int number) {
// we create a base two logarithm of the given value
// Below we swap the base number to base two logarithms!
return (int) (Math.log(number) / Math.log(2)) + 1;
}
}
I would like to know how to update the ranges accordingly, when a user says that the number that they've guessed is higher or lower than what is shown to them.
Edit, example entries:
Looking for number 9,
LL: 1
UL: 10
limit:4
finalNumber:0
midPoint:5
i: 0
Is your number greater than 5?
y
LL: 6
UL: 10
limit:4
finalNumber:6
midPoint:8
i: 1
Is your number greater than 8?
LL: 9
UL: 10
limit:4
finalNumber:9
midPoint:9
i: 2
Is your number greater than 9?
n
LL: 9
UL: 8
limit:4
finalNumber:9
midPoint:8
i: 3
Is your number greater than 8?
y
Your number is : 9
You should not have midPoint--;
Since you are asking the question as "is Grater than"? Your new upper limit should be midpoint if the answer is no.

How can I seperate an array into different 'mags'

I have this project that I have been working on, but I'm a bit rusty so I could use some help to figure out this part.
The main jizt of my project, is that I want to be able to fire a gun at a target and have the target analyze my data.
Before I even start on this, I did some research to find out if anyone else had done this before, and turns out a company in USA have done it, but in a different way than what I imagined..
This is not meant as a business idea, just a fun project for my self :)
Now here is my issue, I ofcourse made a "prototype" without the gun, and without the targets.
All text in Java to see if I could make this work.
I researched a bit since I was rusty (and still am), and figured out most of the problems I faced.
The part that has me stuck is at the very end of it, I have an array for all the shots but I want to divide this array into multiple arrays with the size of the magazine capacity.
How would I accomplish this?
Unfortunately I don't save my code, if I chose to delete it, so my scraps are long gone, but I have tried a few things that came to mind and for several days I havn't been able to figure this one out..
I tried with nested for loops, then I tried again but with nested for loops in a while loop, and I probably tried a few different things aswell.
if (hasrun == true) {
//OUTPUT
ms(2);
System.out.print("You shot the following:");
nl(1);
int counter = 0;
int i = 0;
while (sf > magcap) {
sf-=magcap;
mnm++;
}
while (counter <= mnm) {
System.out.print("Mag " + mn + ": ");
for (i+=0; i < magcap; i++) {
System.out.print(shots[i] + " ");
}
counter++;
mn++;
nl(1);
}
Just to clarify some things in my code here, I know this isn't the cleanest code, I'm not going for clean, and I know I don't need half of my functions (methods), but I did them to practice so they're there. Any help would be greatly appreciated with solving my problem tho! :)
If you want to have a look at all of my code for this project, head over to pastebin
You can use Guava to do it easily,
int[] x = {1,2,3,4,5,6};
int splitSize = 3;
List<Integer> list = IntStream.of(x).boxed().collect(Collectors.toList());
//partition
List<List<Integer>> partitioned = Lists.partition(list, splitSize);
//result: [[1,2,3], [4,5,6]]
Using System.arraycopy:
import java.util.Arrays;
public class Testing {
// static int[] input = {1,2,3,4,5,6}; // testdata
static int[] input = {1,2,3,4,5,6,7}; // testdata
// static int[] input = {1,2,3,4,5,6,7,8}; // testdata
static int magSize = 3; // testdata
// static int magSize = 5; // testdata
public static void main(String[] args) {
// int resultSize = (int) Math.ceil((double) input.length / magSize);
int resultSize = input.length % magSize == 0 ?
input.length/magSize :
input.length/magSize + 1;
int[][] result = new int[resultSize][magSize];
for (int i = 0; i < resultSize; i++) {
System.arraycopy(input, // src
i*magSize, // srcPos
result[i], // dest
0, // destPos
(i + 1) * magSize < input.length ?
magSize :
input.length - i*magSize); // length
}
System.out.println("Original : " + Arrays.toString(input));
System.out.println("Result : " + Arrays.deepToString(result));
/*
prints:
Original : [1, 2, 3, 4, 5, 6, 7]
Result : [[1, 2, 3], [4, 5, 6], [7, 0, 0]]
*/
}
}
I figured it somewhat out, here is what I did. Not quite implemented yet, but this worked with an array.
// OUTPUT
while (sf >= magcap) {
sf -= magcap;
mn++;
}
ms(2);
System.out.println(mn + " mags and " + sf + " shots fired");
nl(2);
for (int i = 0; i < mn; i++) {
from = magcap * magcounter - magcap;
to = magcap * magcounter;
System.out.print("Mag " + magcounter + ": ");
for (int j = from; j < to - 1; j++) {
System.out.print(shots[j] + ", ");
}
System.out.print(shots[to - 1] + ".");
magcounter++;
nl(1);
}
// PRINT THE REST
if (sf >= 1) {
from = magcap * magcounter - magcap;
to = magcap * magcounter;
if (sf == 1) {
System.out.print("Mag " + magcounter + ": ");
System.out.print(shots[from] + ".");
} else {
System.out.print("Mag " + magcounter + ": ");
for (int i = 0; i < sf - 1; i++) {
System.out.print(shots[from + i] + ", ");
}
from += sf -1;
System.out.print(shots[from] + ".");
}
}
The output is
1 2 3 4 5 6 7 8 9 10
3 mags fired and 1 shots fired
Mag 1: 1 2 3
Mag 2: 4 5 6
Mag 3: 7 8 9
Mag 4: 10

Java: Counting Times it takes to generate a given number

So I'm trying to further my knowledge of loops and I'm attempting to satisfy a loop program, ran by a driver.
The final loop to be satisfied should generate a random number between two given bounds, given from the driver, and is to run until the random number is equal to the lower bound. Currently, I'm stuck in an infinite loop.
public void loop4()
{
System.out.println("Loop 4 Output, lowerBound = " + lowerBound +
" upperBound = " + upperBound);
for(int i = 0;i < 10; i++){ //First loop should take 5 trys
int num = (int) (Math.random()* (upperBound - lowerBound));
if(num == lowerBound){
System.out.println(i);
break;
}
else{}
}
System.out.println("-------------");
}
And from the driver:
loopTest.setBounds(9, 9);
loopTest.loop4();
loopTest.setBounds(100, 200);
loopTest.loop4();
loopTest.loop4();
loopTest.loop4();
loopTest.setBounds(100, 50);
loopTest.loop4();
So, of course, I'm simply trying to print the counter, i, once num == lowerBound. However, as stated above, I either get stuck in an infinite loop (when I take the limit away from i, in this case it's at ten, just for the sake of testing), or it simply ignore the loop altogether, and I'm having trouble identifying the problem.
Thanks
I recommend you to use Random library:
import java.util.Random;
public static void loop4()
{
Random rand = new Random();
int lowerBound = 100;
int upperBound = 102;
System.out.println("Loop 4 Output, lowerBound = " + lowerBound +
" upperBound = " + upperBound);
for(int i = 0; i < 10; i++){
// Next line was modified so you get values between lowerBound and upperBound
int num = lowerBound + rand.nextInt(upperBound - lowerBound + 1);
System.out.println(num);
if(num == lowerBound){
System.out.println(i);
break;
}
}
System.out.println("-------------");
}
This isn't really the correct way to approach this problem. Since you are trying to loop an undetermined number of times, calling a method to loop 10 times a piece isn't the best way to solve it.
In this case the "while" loop would be more beneficial, something like:
public void loop4
{
int num;
int i = 0;
while (num != lowerbound)
{
num = (int) (Math.random()* (upperBound - ++lowerBound));
i++;
}
System.out.println(i);
}
This way, you only have to call the loop once
upperBound - lowerBound = 50 - 100 for the latest test.
So you'll get a value between -50 to 0 (excluded) and you try to compare it with 100.

Does Java's Random Object create random numbers through equal opportunity?

I'm trying to write a short program that plays a dice game (normal 6 sided dice) for me. The first roll's number is added to the score. After the first roll, if I roll a 6 then the game stops and the score is recorded (without adding the 6). If a 6 is rolled on the first roll, that's fine and it's added like any other number 1 through 5. I'm trying to run a bunch of iterations of this game such that I have a long list of scores pre-bust (a bust being a rolled 6). I rearrange those scores to be in order from smallest to largest and then find the median of the list which is the score at which it is optimal to stop.
For some reason I keep getting 13 when I run the program but I know for a fact that the answer should be 15. Would using Random in Java would have some sort of effect on the median? I don't exactly know how Random generates the numbers and whether it creates them with equal opportunity. Also, is there anything that just pops out that shouldn't work?
import java.util.*;
public class DiceRoller {
private static Random r = new Random();
private static final int games = 10001;
private static int[] totalScores = new int[games];
private static int index = 0;
public static void main(String[] args) {
int score = 0; boolean firstRoll = true;
while (index < games) {
int roll = roll();
if (firstRoll) {
score += roll;
firstRoll = false;
} else {
if (roll == 6) {
totalScores[index] = score;
index++;
score = 0; firstRoll = true;
} else {
score += roll;
}
}
}
System.out.println("The median is " + median() + ".");
}
public static int roll() {
return r.nextInt(6) + 1;
}
public static int median() {
Arrays.sort(totalScores);
int temp = totalScores[games / 2];
return temp;
}
}
You get 13 because that's the correct result. A little mathematics: if S is the random variable representing the score of any one of these games, then you can consider the Probability generating function f(z) of S. From the description of the game, this probability generating function satisfies the equation:
f(z) = (z + z^2 + z^3 + z^4 + z^5 + z^6) / 36 + f(z)(z + z^2 + z^3 + z^4 + z^5) / 6
This takes a bit of thought, or familiarity with this sort of construction: the left-hand term on the right-hand side takes account of the probabilities of getting 1 through 6 in a simple 2-roll game; the right-hand term involving f(z) takes account of games involving 3 or more rolls, expressing them in terms of the final pre-6 roll (which must be in the range 1 through 5) and the preceding rolls, whose probabilities we can express recursively using f again.
Anyway, after getting this far, one can rearrange to describe f as a rational function of z, and then expand as a power series, which begins:
f(z) = 1/36*z + 7/216*z^2 + 49/1296*z^3 + 343/7776*z^4 + 2401/46656*z^5 + 16807/279936*z^6 + 63217/1679616*z^7 + 388087/10077696*z^8 + 2335585/60466176*z^9 + 13681927/362797056*z^10 + 77103313/2176782336*z^11 + 409031959/13060694016*z^12 + 2371648321/78364164096*z^13 + 13583773735/470184984576*z^14 + ...
(I used Pari/GP to get this.)
The coefficient of z^k then describes the probability of the value of the game being k; thus there's a 1 in 36 chance of the score being 1, a 7 in 216 chance of getting 2, and so on. The sum of the first 12 coefficients is 0.472828864487196328..., while the sum of the first 13 coefficients is 0.5030933144224321950968.... So the median is indeed 13.
To provide an independent check, I wrote a quick Python program:
from __future__ import division
import random
def roll():
return random.randint(1, 6)
def play():
score = roll()
while True:
throw = roll()
if throw == 6:
break
score += throw
return score
all_scores = sorted(play() for _ in xrange(1000001))
print "median is: ",all_scores[len(all_scores) // 2]
print "fraction of scores <= 12: ",all_scores.index(13) / len(all_scores)
print "fraction of scores <= 13: ",all_scores.index(14) / len(all_scores)
Sure enough, here are the results:
iwasawa:~ mdickinson$ python dice_game.py
median is: 13
fraction of scores <= 12: 0.472811527188
fraction of scores <= 13: 0.502863497137
So to answer your question, the results you're seeing are not evidence of any sort of weakness in Java's random number generation.
Random is not perfectly random and has some deficiencies. However for this use case you are very unlikely to notice the difference. You can assume every value 1 to 6 is equally likely.
For comparison here is another solution which counts the number of occurrences of a total rather than recording every value. As you can see this performs well even if you have 1000x more games. This works best when you have a small number of outcomes and a high number duplicates. It is naturally sorted.
import java.util.Random;
public class DiceRoller {
private static final int MAX_VALUE = 300; // assume at most this total
private static final int GAMES = 10000001;
public static void main(String... args) {
int[] count = new int[MAX_VALUE];
Random rand = new Random();
for (int i = 0; i < GAMES; i++)
count[totalScore(rand)]++;
System.out.println("The median is " + median(count, GAMES) + ".");
}
private static int median(int[] count, int games) {
int findTotal = games/2;
for (int i = 0; i < count.length; i++) {
findTotal -= count[i];
if (findTotal <= 0) return i;
}
throw new AssertionError();
}
private static int totalScore(Random rand) {
int total = rand.nextInt(6) + 1;
for(int n;(n = rand.nextInt(6) + 1) != 6;)
total += n;
return total;
}
}
Here is some code that shows you the distribution of the results. It doesn't really answer the question, but maybe it helps you in your research.
package so7297660;
import java.util.Random;
public class DiceRoller {
private static final int N = 10000000;
private static final Random r = new Random();
private static final int[] result = new int[100];
public static int roll() {
return r.nextInt(6) + 1;
}
private static int singleGame() {
int score = roll();
while (true) {
int roll = roll();
if (roll == 6) {
return score;
} else {
score += roll;
}
}
}
private static int median() {
int n = 0;
for (int i = 0; i < result.length; i++) {
if (n + result[i] >= N / 2) {
return i;
}
n += result[i];
}
throw new IllegalStateException();
}
public static void main(String[] args) {
for (int i = 0; i < N; i++) {
int score = singleGame();
int index = Math.min(score, result.length - 1);
result[index]++;
}
for (int i = 0; i < result.length; i++) {
System.out.println(i + "\t" + result[i]);
}
System.out.println("median\t" + median());
}
}

How to count possible combination for coin problem

I am trying to implement a coin problem, Problem specification is like this
Create a function to count all possible combination of coins which can be used for given amount.
All possible combinations for given amount=15, coin types=1 6 7
1) 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2) 1,1,1,1,1,1,1,1,1,6,
3) 1,1,1,1,1,1,1,1,7,
4) 1,1,1,6,6,
5) 1,1,6,7,
6) 1,7,7,
function prototype:
int findCombinationsCount(int amount, int coins[])
assume that coin array is sorted. for above example this function should return 6.
Anyone guide me how to implement this??
Use recursion.
int findCombinationsCount(int amount, int coins[]) {
return findCombinationsCount(amount, coins, 0);
}
int findCombinationsCount(int amount, int coins[], int checkFromIndex) {
if (amount == 0)
return 1;
else if (amount < 0 || coins.length == checkFromIndex)
return 0;
else {
int withFirstCoin = findCombinationsCount(amount-coins[checkFromIndex], coins, checkFromIndex);
int withoutFirstCoin = findCombinationsCount(amount, coins, checkFromIndex+1);
return withFirstCoin + withoutFirstCoin;
}
}
You should check this implementation though. I don't have a Java IDE here, and I'm a little rusty, so it may have some errors.
Although recursion can work and is often an assignment to implement in some college level courses on Algorithms & Data Structures, I believe the "dynamic programming" implementation is more efficient.
public static int findCombinationsCount(int sum, int vals[]) {
if (sum < 0) {
return 0;
}
if (vals == null || vals.length == 0) {
return 0;
}
int dp[] = new int[sum + 1];
dp[0] = 1;
for (int i = 0; i < vals.length; ++i) {
for (int j = vals[i]; j <= sum; ++j) {
dp[j] += dp[j - vals[i]];
}
}
return dp[sum];
}
You can use generating function methods to give fast algorithms, which use complex numbers.
Given the coin values c1, c2, .., ck, to get the number of ways to sum n, what you need is the coefficient of x^n in
(1 + x^c1 + x^(2c1) + x^(3c1) + ...)(1+x^c2 + x^(2c2) + x^(3c2) + ...)....(1+x^ck + x^(2ck) + x^(3ck) + ...)
Which is the same as finding the coefficient of x^n in
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
Now using complex numbers, x^a - 1 = (x-w1)(x-w2)...(x-wa) where w1, w2 etc are the complex roots of unity.
So
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
can be written as
1/(x-a1)(x-a2)....(x-am)
which can be rewritten using partial fractions are
A1/(x-a1) + A2/(x-a2) + ... + Am/(x-am)
The coefficient of x^n in this can be easily found:
A1/(a1)^(n+1) + A2/(a2)^(n+1) + ...+ Am/(am)^(n+1).
A computer program should easily be able to find Ai and ai (which could be complex numbers). Of course, this might involve floating point computations.
For large n, this will be probably faster than enumerating all the possible combinations.
Hope that helps.
Very simple with recursion:
def countChange(money: Int, coins: List[Int]): Int = {
def reduce(money: Int, coins: List[Int], accCounter: Int): Int = {
if(money == 0) accCounter + 1
else if(money < 0 || coins.isEmpty) accCounter
else reduce(money - coins.head, coins, accCounter) + reduce(money, coins.tail, accCounter)
}
if(money <= 0 || coins.isEmpty) 0
else reduce(money, coins, 0)
}
This is example in SCALA
Aryabhatta’s answer for
counting the number of ways to make change with coins of fixed
denominations is very cute but also impractical to implement as
described. Rather than use complex numbers, we’ll use modular
arithmetic, similar to how the number-theoretic transform replaces a
Fourier transform for multiplying integer polynomials.
Let D be the least common multiple of the coin denominations. By
Dirichlet’s theorem on arithmetic progressions, there exist infinitely
many prime numbers p such that D divides p - 1. (With any luck,
they’ll even be distributed in a way such that we can find them
efficiently.) We’ll compute the number of ways modulo some p
satisfying this condition. By obtaining a crude bound somehow (e.g.,
n + k - 1 choose k - 1 where n is the total and k is the number
of denominations), repeating this procedure with several different
primes whose product exceeds that bound, and applying the Chinese
remainder theorem, we can recover the exact number.
Test candidates 1 + k*D for integers k > 0 until we find a prime
p. Let g be a primitive root modulo p (generate candidates at
random and apply the standard test). For each denomination d, express
the polynomial x**d - 1 modulo p as a product of factors:
x**d - 1 = product from i=0 to d-1 of (x - g**((p-1)*i/d)) [modulo p].
Note that d divides D divides p-1, so the exponent indeed is an
integer.
Let m be the sum of denominations. Gather all of the constants
g**((p-1)*i/d) as a(0), ..., a(m-1). The next step is to find a
partial fraction decomposition A(0), ..., A(m-1) such that
sign / product from j=0 to m-1 of (a(j) - x) =
sum from j=0 to m-1 of A(j)/(a(j) - x) [modulo p],
where sign is 1 if there are an even number of denominations and
-1 if there are an odd number of denominations. Derive a system of
linear equations for A(j) by evaluating both sides of the given
equation for different values of x, then solve it with Gaussian
elimination. Life gets complicated if there are duplicates; it's probably easiest just to pick another prime.
Given this setup, we can compute the number of ways (modulo p, of
course) to make change amounting to n as
sum from j=0 to m-1 of A(j) * (1/a(j))**(n+1).
The recursive solutions mentioned will work, but they're going to be horrendously slow if you add more coin denominations and/or increase the target value significantly.
What you need to speed it up is to implement a dynamic programming solution. Have a look at the knapsack problem. You can adapt the DP solution mentioned there to solve your problem by keeping a count of the number of ways a total can be reached rather than the minimum number of coins required.
package algorithms;
import java.util.Random;
/**`enter code here`
* Owner : Ghodrat Naderi
* E-Mail: Naderi.ghodrat#gmail.com
* Date : 10/12/12
* Time : 4:50 PM
* IDE : IntelliJ IDEA 11
*/
public class CoinProblem
{
public static void main(String[] args)
{
int[] coins = {1, 3, 5, 10, 20, 50, 100, 200, 500};
int amount = new Random().nextInt(10000);
int coinsCount = 0;
System.out.println("amount = " + amount);
int[] numberOfCoins = findNumberOfCoins(coins, amount);
for (int i = 0; i < numberOfCoins.length; i++)
{
if (numberOfCoins[i] > 0)
{
System.out.println("coins= " + coins[i] + " Count=" + numberOfCoins[i] + "\n");
coinsCount += numberOfCoins[i];
}
}
System.out.println("numberOfCoins = " + coinsCount);
}
private static int[] findNumberOfCoins(int[] coins, int amount)
{
int c = coins.length;
int[] numberOfCoins = new int[coins.length];
while (amount > 0)
{
c--;
if (amount >= coins[c])
{
int quotient = amount / coins[c];
amount = amount - coins[c] * quotient;
numberOfCoins[c] = quotient;
}
}
return numberOfCoins;
}
}
A recursive solution might be the right answer here:
int findCombinationsCount(int amount, int coins[])
{
// I am assuming amount >= 0, coins.length > 0 and all elements of coins > 0.
if (coins.length == 1)
{
return amount % coins[0] == 0 ? 1 : 0;
}
else
{
int total = 0;
int[] subCoins = arrayOfCoinsExceptTheFirstOne(coins);
for (int i = 0 ; i * coins[0] <= amount ; ++i)
{
total += findCombinationsCount(amount - i * coins[0], subCoins);
}
return total;
}
}
Warning: I haven't tested or even compiled the above.
The solution provided by #Jordi is nice but runs extremely slow. You can try input 600 to that solution and see how slow it is.
My idea is to use bottom-up dynamic programming.
Note that generally, the possible combination for money=m and coins{a,b,c} equals combination for
m-c and coins{a,b,c} (with coin c)
combination for m and coins{a,b} (without coin c).
If no coins are available or available coins can not cover the required amount of money, it should fill in 0 to the block accordingly. If the amount of money is 0, it should fill in 1.
public static void main(String[] args){
int[] coins = new int[]{1,2,3,4,5};
int money = 600;
int[][] recorder = new int[money+1][coins.length];
for(int k=0;k<coins.length;k++){
recorder[0][k] = 1;
}
for(int i=1;i<=money;i++){
//System.out.println("working on money="+i);
int with = 0;
int without = 0;
for(int coin_index=0;coin_index<coins.length;coin_index++){
//System.out.println("working on coin until "+coins[coin_index]);
if(i-coins[coin_index]<0){
with = 0;
}else{
with = recorder[i-coins[coin_index]][coin_index];
}
//System.out.println("with="+with);
if(coin_index-1<0){
without = 0;
}else{
without = recorder[i][coin_index-1];
}
//System.out.println("without="+without);
//System.out.println("result="+(without+with));
recorder[i][coin_index] = with+without;
}
}
System.out.print(recorder[money][coins.length-1]);
}
This code is based on the solution provided by JeremyP which is working perfect and I just enhanced it to optimize the performance by using dynamic programming.I couldn't comment on the JeremyP post because I don't have enough reputation :)
public static long makeChange(int[] coins, int money) {
Long[][] resultMap = new Long[coins.length][money+1];
return getChange(coins,money,0,resultMap);
}
public static long getChange(int[] coins, int money, int index,Long[][] resultMap) {
if (index == coins.length -1) // if we are at the end
return money%coins[index]==0? 1:0;
else{
//System.out.printf("Checking index %d and money %d ",index,money);
Long storedResult =resultMap[index][money];
if(storedResult != null)
return storedResult;
long total=0;
for(int coff=0; coff * coins[index] <=money; coff ++){
total += getChange(coins, money - coff*coins[index],index +1,resultMap);
}
resultMap[index][money] = total;
return total;
}
}
First idea:
int combinations = 0;
for (int i = 0; i * 7 <=15; i++) {
for (int j = 0; j * 6 + i * 7 <= 15; j++) {
combinations++;
}
}
(the '<=' is superfluous in this case, but is needed for a more general solution, if you decide to change your parameters)
Below is recursion with memoization java solution. for below one we have 1,2,3,5 as coins and 200 as the target amount.
countCombinations(200,new int[]{5,2,3,1} , 0, 0,new Integer[6][200+5]);
static int countCombinations(Integer targetAmount, int[] V,int currentAmount, int coin, Integer[][] memory){
//Comment below if block if you want to see the perf difference
if(memory[coin][currentAmount] != null){
return memory[coin][currentAmount];
}
if(currentAmount > targetAmount){
memory[coin][currentAmount] = 0;
return 0;
}
if(currentAmount == targetAmount){
return 1;
}
int count = 0;
for(int selectedCoin : V){
if(selectedCoin >= coin){
count += countCombinations(targetAmount, V, currentAmount+selectedCoin, selectedCoin,memory);
}
}
memory[coin][currentAmount] = count;
return count;
}
#include<iostream>
using namespace std;
int solns = 0;
void countComb(int* arr, int low, int high, int Val)
{
bool b = false;
for (size_t i = low; i <= high; i++)
{
if (Val - arr[i] == 0)
{
solns++;
break;
}
else if (Val - arr[i] > 0)
countComb(arr, i, high, Val - arr[i]);
}
}
int main()
{
int coins[] = { 1,2,5 };
int value = 7;
int arrSize = sizeof(coins) / sizeof(int);
countComb(coins,0, arrSize,value);
cout << solns << endl;
return 0;
}
Again using recursion a tested solution, though probably not the most elegant code. (note it returns the number of each coin to use rather than repeating the actual coin ammount n times).
public class CoinPerm {
#Test
public void QuickTest() throws Exception
{
int ammount = 15;
int coins[] = {1,6,7};
ArrayList<solution> solutionList = SolvePerms(ammount, coins);
for (solution sol : solutionList)
{
System.out.println(sol);
}
assertTrue("Wrong number of solutions " + solutionList.size(),solutionList.size() == 6);
}
public ArrayList<solution> SolvePerms(int ammount, int coins[]) throws Exception
{
ArrayList<solution> solutionList = new ArrayList<solution>();
ArrayList<Integer> emptyList = new ArrayList<Integer>();
solution CurrentSolution = new solution(emptyList);
GetPerms(ammount, coins, CurrentSolution, solutionList);
return solutionList;
}
private void GetPerms(int ammount, int coins[], solution CurrentSolution, ArrayList<solution> mSolutions) throws Exception
{
int currentCoin = coins[0];
if (currentCoin <= 0)
{
throw new Exception("Cant cope with negative or zero ammounts");
}
if (coins.length == 1)
{
if (ammount % currentCoin == 0)
{
CurrentSolution.add(ammount/currentCoin);
mSolutions.add(CurrentSolution);
}
return;
}
// work out list with one less coin.
int coinsDepth = coins.length;
int reducedCoins[] = new int[(coinsDepth -1 )];
for (int j = 0; j < coinsDepth - 1;j++)
{
reducedCoins[j] = coins[j+1];
}
// integer rounding okay;
int numberOfPerms = ammount / currentCoin;
for (int j = 0; j <= numberOfPerms; j++)
{
solution newSolution = CurrentSolution.clone();
newSolution.add(j);
GetPerms(ammount - j * currentCoin,reducedCoins, newSolution, mSolutions );
}
}
private class solution
{
ArrayList<Integer> mNumberOfCoins;
solution(ArrayList<Integer> anumberOfCoins)
{
mNumberOfCoins = anumberOfCoins;
}
#Override
public String toString() {
if (mNumberOfCoins != null && mNumberOfCoins.size() > 0)
{
String retval = mNumberOfCoins.get(0).toString();
for (int i = 1; i< mNumberOfCoins.size();i++)
{
retval += ","+mNumberOfCoins.get(i).toString();
}
return retval;
}
else
{
return "";
}
}
#Override
protected solution clone()
{
return new solution((ArrayList<Integer>) mNumberOfCoins.clone());
}
public void add(int i) {
mNumberOfCoins.add(i);
}
}
}
Dynamic Programming Solution
Given an array of denominations D = {d1, d2, d3, ... , dm} and a target amount W. Note that D doesn't need to be sorted.
Let T(i, j) be the number of combinations that make up amount j using only denominations on the left of the ith one (can include itself) in D.
We have:
T(0, 0) = 1 : since the amount is 0, there is only 1 valid combination that makes up 0, which is the empty set.
T(i, j) = T(i - 1, j) if D[i] > j
T(i, j) = T(i - 1, j) + T(i, j - D[i]) if D[i] <= j
public int change(int amount, int[] coins) {
int m = coins.length;
int n = amount;
int[][] dp = new int[m + 1][n + 1];
dp[0][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (j < coins[i - 1]) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
int b,c,total = 15;
int combos =1;
for(int d=0;d<total/7;d++)
{
b = total - d * 7;
for (int n = 0; n <= b /6; n++)
{
combos++;
}
}
System.out.print("TOTAL COMBINATIONS = "+combos);
}
Below is a recursive backtracking solution I created, It lists and counts all possible combination of denominations (coins) that would add up to a given amount.
Both denominations and the amounts can be dynamic
public class CoinComboGenerate {
public static final int[] DENO = {1,6,7};
public static final int AMOUNT = 15;
public static int count = 0;
public static void change(int amount) {
change(amount, new ArrayList<>(),0);
}
private static void change(int rem, List<Integer> coins, int pos) {
if (rem == 0) {
count++;
System.out.println(count+")"+coins);
return;
}
while(pos<DENO.length){
if (rem >= DENO[pos]) {
coins.add(DENO[pos]);
change(rem - DENO[pos], coins,pos);
coins.remove(coins.size() - 1); //backtrack
}
pos++;
}
}
public static void main(String[] args) {
change(AMOUNT);
}
}
Output:
1)[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
2)[1, 1, 1, 1, 1, 1, 1, 1, 1, 6]
3)[1, 1, 1, 1, 1, 1, 1, 1, 7]
4)[1, 1, 1, 6, 6]
5)[1, 1, 6, 7]
6)[1, 7, 7]
The same problem for coins(1,5,10,25,50) has one of below solutions.
The solution should satisfy below equation:
1*a + 5*b + 10*c + 25*d + 50*e == cents
public static void countWaysToProduceGivenAmountOfMoney(int cents) {
for(int a = 0;a<=cents;a++){
for(int b = 0;b<=cents/5;b++){
for(int c = 0;c<=cents/10;c++){
for(int d = 0;d<=cents/25;d++){
for(int e = 0;e<=cents/50;e++){
if(1*a + 5*b + 10*c + 25*d + 50*e == cents){
System.out.println("1 cents :"+a+", 5 cents:"+b+", 10 cents:"+c);
}
}
}
}
}
}
}
This can be modified for any general solutions.

Categories

Resources