-2

So for example to get to a value of 237 given a denomination set of 1, 2, 5, 10, 20, 50 the optimal way to make up the value would be 4x50 + 1x20 + 1x10 + 1x5 + 1x2. But how to achieve that programatically in PHP?

  • 1
    [What you have tried?](http://mattgemmell.com/2008/12/08/what-have-you-tried/) – Jason McCreary Aug 29 '13 at 14:26
  • Show us what you have tried so far. Quick: loop over your amount and deduct the "biggest" coin, until you reach zero. – Bart Friederichs Aug 29 '13 at 14:27
  • 1
    possible duplicate of [Coin change problem with infinite number of coins of each denomination](http://stackoverflow.com/questions/1518330/coin-change-problem-with-infinite-number-of-coins-of-each-denomination) – dcro Aug 29 '13 at 14:27
  • Is this your homeworks ? – Brewal Aug 29 '13 at 14:28
  • @ Brewal - Are you grooming me? – Nick Thompson Aug 29 '13 at 15:39
  • @NickThompson If I was, I would not give you the solution below. I was just joking. By the way, you should not ask a question without trying anything by yourself. I'm still kind enough to give you an answer. – Brewal Aug 29 '13 at 15:41

1 Answers1

1

You could do something like this :

$number = 237;

$values = array(1, 2, 5, 10, 20, 50);
arsort($values); // greater to lower sorting
$numberOf = array();

foreach ($values as $v) {
    $numberOf[$v] = floor($number / $v);
    $number -= $numberOf[$v] * $v;
}

var_dump($numberOf);

This will produce :

array(6) {
  [50]=>
  int(4)
  [20]=>
  int(1)
  [10]=>
  int(1)
  [5]=>
  int(1)
  [2]=>
  int(1)
  [1]=>
  int(0)
}

the demo

Edit : Denominations with finit amounts

If you don't have infinit denominations, you can try this :

$number = 237;

$values = array(1, 2, 5, 10, 20, 50);
$quantities = array(7, 1, 3, 5, 2, 3);
// sort by greater value to lower value
// but keeping the related quantities
array_multisort($values, SORT_DESC, $quantities);

$numberOf = array();

foreach ($values as $i => $v) {
    $quantity = $quantities[$i]; // get the corresponding quantity
    // if we have less than the required value, we put the max we can
    $numberOf[$v] = floor($number / $v) > $quantity ? $quantity : floor($number / $v);
    $number -= $numberOf[$v] * $v;
}

var_dump($numberOf);

In this example, you only have a quantity of 3 for 50. So you will have an output like :

array(6) {
  [50]=>
  int(3)
  [20]=>
  int(2)
  [10]=>
  float(4)
  [5]=>
  float(1)
  [2]=>
  float(1)
  [1]=>
  float(0)
}

3 * 50 + 2 * 20 + 4 * 10 + 5 * 1 + 2 * 1 + 1 * 0 = 237

Yippee !
The demo

See also array_multisort() to understand this key line :

array_multisort($values, SORT_DESC, $quantities);

And even better, a ready to go function :

function getDenominations($amount, $denominations, $quantities = null) {
    if (is_array($quantities) && count($denominations) != count($quantities)) return false;
    array_multisort($denominations, SORT_DESC, $quantities);

    $numberOf = array();

    foreach ($denominations as $i => $v) {
        $quantity = $quantities[$i]; 
        $numberOf[$v] = floor($amount/ $v) > $quantity ? $quantity : floor($amount / $v);
        $amount -= $numberOf[$v] * $v;
    }

    return $amount == 0 ? $numberOf : false;
}

To use like this :

$result = getDenominations(
    237,
    array(1, 2, 5, 10, 20, 50),
    array(7, 1, 3, 5, 0, 4)
);

var_dump($result);

Return values : array|bool

If no quantity is specified, it returns the denominations with infinite amount. If specified, with finite amount.
Returns "false" whether there's not enough quantities or if the sizes of the arrays are different.

Brewal
  • 8,067
  • 2
  • 24
  • 37
  • Thanks Brewal this works. The particular sticky problem I'm having is that the denominations don't come in infinite amounts. They are finite. So I may have 7x1, 3X2, 6x5, 9x10, 1x20, 2x50. How to calculate the end value while some denominations may not be available in quantity needed? That's the real problem! – Nick Thompson Aug 29 '13 at 15:59