Coin change problem with infinite number of coins of each denomination

半城伤御伤魂 提交于 2019-11-28 08:50:51

I would think about building the solution one step at a time, inductively:

Coins available are 1c, 5c, 10c, 25c (you can tweak them according to your needs)

  1. Minimun coins for 1c = 1 X 1c. Upto 4 cents, we need 1c coins, as that is the least denomination.
  2. For 5 cents, we have one 5c coin. Combining that with 4c above, we can generate any number between 1 and 9.
  3. For 10 cents, we need 1 X 10c. Combining the above three, we can generate any number between 1 and 19.
  4. For 20c, we need 2 x 10c, as 20 is divisible by 10.

If you can formulate the problem inductively, it might be easier to tackle it.

EDIT:
Alright, here's another attempt to explain the dynamic programming solution:

Think of a table with x rows (x is number of distinct denominations) and n columns (n is the amount you have to build using least denominations). Every cell in this table represents a distinct sub-problem and will eventually contain the solution to it. Assume:

row 1 represents the set {1c} i.e. in row 1 you are allowed to use infinite 1c
row 2 represents the set {1c, 10c} i.e in row 2 you are allowed to infinite 1c and 10c
row 3 represents the set {1c, 10c, 15c} and so on...
Each column represents the amount you want to construct.

Thus, every cell corresponds to one small sub-problem. For example (the indexes are starting from 1 for the sake of simplicity),
cell(1, 5) ==> construct 5c using only {1c}
cell(2, 9) ==> construct 9c using {1c, 10c}
cell(3, 27) ==> construct 27c using {1c, 10c, 15c}
Now your aim is to get the answer to cell(x, n)

Solution:
Start solving the table from the simplest problem. Solving the first row is trivial, since in the first row the only denomination available is {1c}. Every cell in row 1 has a trivial solution, leading to cell(1, n) = {nx1c} (n coins of 1c).

Now proceed to the next row. Generalizing for the 2nd row, lets see how to solve for (say) cell(2, 28) i.e. construct 28c using {1c, 10c}. Here, you need to make a decision, whether to include 10c in the solution or not, and how many coins. You have 3 choices (3 = 28/10 + 1)

Choice 1:
Take {1x10c} and the rest from the previous row (which is stored in cell(1, 18)). This gives you {1x10c, 18x1c} = 19 coins

Choice 2:
Take {2x10c} and the rest from previous row (which is stored in cell(1, 8)). This gives you {2x10c, 8x1c} = 10 coins

Choice 3:
Take no 10c and the rest from the previous row (which is stored in cell(1, 28)). This gives you {28x1c} = 28 coins

Clearly, choice 2 is the best as it takes less coins. Write it down in the table and proceed ahead. The table is to be filled one row at a time, and within a row, in the order of increasing amounts.

Going by above rules, you will reach cell(x, n), the solution to which will be a choice between n/p + 1 alternatives, where p = newest denomination in row x. The best choice is your answer.

The table actually memoizes the solutions to smaller problems, so that you don't need to solve them again and again.

about the brute force part:

int i,j,k;
for(i=0;i<35;i++){
  for(j=0;j<4;j++){
    for(k=0;k<3;k++){
      if(1*i+10*j+15*k == 35){
        //is this what you need?
        //minimum=min(minimum,(i+j+k));
      }
    }
  }
}

This is how to translate a number from one numbering system to another. For example:

35 = 1*2^5 + 0*2^4 + 0*2^3 + 0*2^2 + 0*2^1 + 1*2^0

That is:

var cash = 35;
var coins = [15, 10, 5, 1];
var change = {};
for(var i=0; i<coins.length; i++){
  change[coins[i]]  = Math.floor(cash/coins[i]);
  cash %= coins[i];
}
//change now contains:
//15:2, 10:0, 5:1, 1:0
Olexiy

Regarding the brute force.

It is called "greedy algorithm" - you always take the biggest coin which is not greater than the value you need to represent.

pseudo code, returns the number of coins needed to represent value, if we can use each one infinite number of times

int[] greedy(int value, int[] coins) {
   int[] ans = ...;
   int v = coins.length - 1;
   int left = value;
   while (left > 0 && v >= 0) {
       if (coins[v] <= left) {
           ans.push(coins[v]);
       } else { 
           v--;
       }
   }
   return left == 0 ? ans : //representation impossible, 
                            //so you better do something;
}

pseudo code, returns the number of coins needed to represent value, if we can use each one infinite number of times

int f(int value, int[] coins) {
   int[] memo = new int[value + 1];
   Arrays.fill(memo, 1234567);
   memo[0] = 0;
   for (int coin : coins)
       for (int i = 0; i + coin <= value; i++)
           memo[i + coin] = min(memo[i + coin], memo[i] + 1);
   return memo[value];
}

to know which coins to take, start from the end: if memo[value] = 3, then you check all coins and find such coin that memo[value - coin] == 2, continue from (value - coin) until you reach 0.

You can run it here http://www.exorithm.com/algorithm/view/coin_change

function coin_change ($amount, $coins)
{
  $change = array();
  rsort($coins);
  for($i=0; $i<count($coins); $i++) {
    $change[$coins[$i]] = floor($amount/$coins[$i]);
    $amount = $amount % $coins[$i];
  }
  return $change;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!