views:

667

answers:

13

Recently I challenged my co-worker to write an algorithm to solve this problem:

Find the least number of coins required that can make any change from 1 to 99 cents. The coins can only be pennies (1), nickels (5), dimes (10), and quarters (25), and you must be able to make every value from 1 to 99 (in 1-cent increments) using those coins.

However, I realized that I don't actually know how to do this myself without examining every possible combination of coins. There has to be a better way of solving this problem, but I don't know what the generic name for this type of algorithm would be called, and I can't figure out a way to simplify it beyond looking at every solution.

I was wondering if anybody could point me in the right direction, or offer up an algorithm that's more efficient.

+1  A: 

This should help: Optimal change-carrying And a very similar question on SO (which is closed as off-topic).

Zabba
not sure why the other question was closed...(algorithms are perfectly programming related).. its not very helpful when there are no answers.
Mark
I think the other question was closed just because it was poorly worded.
Gabe
+3  A: 

Assuming you're talking about US currency, you would want a Greedy Algorithm: http://en.wikipedia.org/wiki/Greedy_algorithm

In essence, you try all denominations from highest-to-lowest, taking as many coins as posible from each one until you've got nothing left.

For the general case see http://en.wikipedia.org/wiki/Change-making_problem, because you would want to use dynamic programming or linear programming to find the answer for arbitrary denominations where a greedy algorithm wouldn't work.

Gabe
from that wikipedia page "if the coin denominations were 1, 3 and 4, then to make 6, the greedy algorithm would choose three coins (4,1,1) whereas the optimal solution is two coins (3,3)" -- neither of those solutions seem correct though. in the former you can't produce 3, and in the latter you can't produce 1,2,4 or 5. the OP says you need to be able to produce *every* value <= X (generalizing)
Mark
Mark: You may be the only one who noticed that the OP is asking for coins that work for *every* value in a range. In any event, the Wikipedia article is talking about the coins to make up a single value, not every value (as the OP is apparently requesting).
Gabe
Yes..which makes it not so helpful :) Your edit sounds like a brute force algorithm...also not a very elegant solution..if there even is one.
Mark
Mark: You have to either loop through every target value to find what set of coins it needs or loop through every permutation of a set of coins to find what values they cover. I believe the former is what I suggested and the latter would be considered brute force.
Gabe
+5  A: 

You can very quickly find an upper bound.

Say, you take three quarters. Then you would only have to fill in the 'gaps' 1-24, 26-49, 51-74, 76-99 with other coins.

Trivially, that would work with 2 dimes, 1 nickel, and 4 pennies.

So, 3 + 4 + 2 + 1 should be an upper bound for your number of coins, Whenever your brute-force algorithm goes above thta, you can instantly stop searching any deeper.

The rest of the search should perform fast enough for any purpose with dynamic programming.

(edit: fixed answer as per Gabe's observation)

Thomas
3+4+2=9 but I'm pretty sure the OP's looking for 10 coins.
Gabe
@Gabe: Why do you think that? Do you have a value that cannot be composed of 9 or less coins? edit: Right! I disregarded values like 15-19. ;) Answer will be edited.
Thomas
Yes, I believe that about 40% of the values will require a nickel.
Gabe
@Gabe: Gotcha. Power of posting immediately let me know what you were hinting at in your first answer. It's already fixed. Thanks for the heads-up!
Thomas
Well, the problem is that the OP is asking for an algorithm to compute that upper bound. You've outright told him the answer without telling him how to compute it.
Gabe
@Gabe: No, he wasn't. He was asking for a pointer in the right direction. I've given him an (obvious) upper bound, to keep his already existing brute-force idea from going too deep, plus a suggestion to look into dynamic programming. From my perspective, that was a hint, and that's exactly what he asked for.
Thomas
I already figured out the answer manually, but didn't know how to convert the thought process to an algorithm. We're thinking of using it as an interview question now, but it'd be good to know how to write it ourselves before asking the interviewees!
Daniel T.
+1  A: 

This might be a generic solution in C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoinProblem
{
    class Program
    {
        static void Main(string[] args)
        {
            var coins = new int[] { 1, 5, 10, 25 }; // sorted lowest to highest
            int upperBound = 99;
            int numCoinsRequired = upperBound / coins.Last();
            for (int i = coins.Length - 1; i > 0; --i)
            {
                numCoinsRequired += coins[i] / coins[i - 1] - (coins[i] % coins[i - 1] == 0 ? 1 : 0);
            }
            Console.WriteLine(numCoinsRequired);
            Console.ReadLine();
        }
    }
}

I haven't fully thought it through...it's too late at night. I thought the answer should be 9 in this case, but Gabe said it should be 10... which is what this yields. I guess it depends how you interpret the question... are we looking for the least number of coins that can produce any value <= X, or the least number of coins that can produce any value <= X using the least number of coins? For example... I'm pretty sure we can make any value with only 9 coins, without nickels, but then to produce 9... you need...oh... I see. You'd need 9 pennies, which you don't have, because that's not what we chose... in that case, I think this answer is right. Just a recursive implementation of Thomas' idea, but I don't know why he stopped there.. you don't need to brute force anything.

Edit: This be wrong.

Mark
Unfortunately, your algorithm doesn't work (nor does mine) for 25. We assume that we need a quarter, when the 2 dimes and a nickel we already have are sufficient.
Gabe
@Gabe Is the question "can we make 25 cents from two dimes and a nickel" or "is the smallest number of coins for 25 cents a quarter"?
Vatine
Vatine: The question is something like "Given that I want to walk around with the fewest coins in my pocket, how many do I need to have exact change for 1 to 25 cents?" Since I already need a nickel to have exact change for 5 cents and I need two dimes to have 20 cents, I will not need a quarter to have 25 cents.
Gabe
@Gabe: Yeah.. I noticed that shortly after I left my computer.
Mark
A: 

EDIT: the first solution I posted (see below) uses 99 iterations to derive its answer. A simpler way would be to determine all the possible combinations between 1 and the max unit (a quarter, in this case).

Then, your algorithm becomes:

Let X = total amount (99)
Let Q = largest unit (25)
Assume remainders are ignored, e.g. 24 / 25 = 0, 26 / 25 = 1

(X / Q) + (max number of combinations between 1 and (Q -1))

In the case of 99, this gives you 10 coins needed, as validated by the brute force method.

The brute force method...

using System;

namespace CountingCoins
{
    class Program
    {
        static void Main( string[] args )
        {
            int maxQuarters = 0;
            int maxDimes = 0;
            int maxNickels = 0;
            int maxPennies = 0;

            for( int i = 1; i < 100; i++ )
            {
                ChangeCombination cc = GetBestCombination( i );

                maxQuarters = cc.Quarters > maxQuarters ? cc.Quarters : maxQuarters;
                maxDimes = cc.Dimes > maxDimes ? cc.Dimes : maxDimes;
                maxNickels = cc.Nickels > maxNickels ? cc.Nickels : maxNickels;
                maxPennies = cc.Pennies > maxPennies ? cc.Pennies : maxPennies;

                Console.WriteLine( cc.ToString() );
            }

            Console.WriteLine( "Max Quarters Needed for any combo: " + maxQuarters);
            Console.WriteLine( "Max Dimes Needed for any combo: " + maxDimes );
            Console.WriteLine( "Max Nickels Needed for any combo: " + maxNickels );
            Console.WriteLine( "Max Pennies Needed for any combo: " + maxPennies );

            Console.ReadLine();
        }


        static ChangeCombination GetBestCombination( int amount )
        {
            ChangeCombination retVal = new ChangeCombination();

            retVal.Quarters = amount / 25;
            amount -= retVal.Quarters * 25;

            retVal.Dimes = amount / 10;
            amount -= retVal.Dimes * 10;

            retVal.Nickels = amount / 5;
            amount -= retVal.Nickels * 5;

            retVal.Pennies = amount;

            return retVal;
        }
    }

    struct ChangeCombination
    {
        public int Pennies;
        public int Nickels;
        public int Dimes;
        public int Quarters;

        public override string ToString()
        {
            int cents = (this.Quarters * 25) + (this.Dimes * 10) + (this.Nickels * 5) + this.Pennies;
            string retVal = this.Quarters + "/" + this.Dimes + "/" + this.Nickels + "/" + this.Pennies + " = " + cents;

            return retVal;
        }
    }
}

And the output...

0/0/0/1 = 1
0/0/0/2 = 2
0/0/0/3 = 3
0/0/0/4 = 4
0/0/1/0 = 5
0/0/1/1 = 6
0/0/1/2 = 7
0/0/1/3 = 8
0/0/1/4 = 9
0/1/0/0 = 10
0/1/0/1 = 11
0/1/0/2 = 12
0/1/0/3 = 13
0/1/0/4 = 14
0/1/1/0 = 15
0/1/1/1 = 16
0/1/1/2 = 17
0/1/1/3 = 18
0/1/1/4 = 19
0/2/0/0 = 20
0/2/0/1 = 21
0/2/0/2 = 22
0/2/0/3 = 23
0/2/0/4 = 24
1/0/0/0 = 25
1/0/0/1 = 26
1/0/0/2 = 27
1/0/0/3 = 28
1/0/0/4 = 29
1/0/1/0 = 30
1/0/1/1 = 31
1/0/1/2 = 32
1/0/1/3 = 33
1/0/1/4 = 34
1/1/0/0 = 35
1/1/0/1 = 36
1/1/0/2 = 37
1/1/0/3 = 38
1/1/0/4 = 39
1/1/1/0 = 40
1/1/1/1 = 41
1/1/1/2 = 42
1/1/1/3 = 43
1/1/1/4 = 44
1/2/0/0 = 45
1/2/0/1 = 46
1/2/0/2 = 47
1/2/0/3 = 48
1/2/0/4 = 49
2/0/0/0 = 50
2/0/0/1 = 51
2/0/0/2 = 52
2/0/0/3 = 53
2/0/0/4 = 54
2/0/1/0 = 55
2/0/1/1 = 56
2/0/1/2 = 57
2/0/1/3 = 58
2/0/1/4 = 59
2/1/0/0 = 60
2/1/0/1 = 61
2/1/0/2 = 62
2/1/0/3 = 63
2/1/0/4 = 64
2/1/1/0 = 65
2/1/1/1 = 66
2/1/1/2 = 67
2/1/1/3 = 68
2/1/1/4 = 69
2/2/0/0 = 70
2/2/0/1 = 71
2/2/0/2 = 72
2/2/0/3 = 73
2/2/0/4 = 74
3/0/0/0 = 75
3/0/0/1 = 76
3/0/0/2 = 77
3/0/0/3 = 78
3/0/0/4 = 79
3/0/1/0 = 80
3/0/1/1 = 81
3/0/1/2 = 82
3/0/1/3 = 83
3/0/1/4 = 84
3/1/0/0 = 85
3/1/0/1 = 86
3/1/0/2 = 87
3/1/0/3 = 88
3/1/0/4 = 89
3/1/1/0 = 90
3/1/1/1 = 91
3/1/1/2 = 92
3/1/1/3 = 93
3/1/1/4 = 94
3/2/0/0 = 95
3/2/0/1 = 96
3/2/0/2 = 97
3/2/0/3 = 98
3/2/0/4 = 99
Max Quarters Needed for any combo: 3
Max Dimes Needed for any combo: 2
Max Nickels Needed for any combo: 1
Max Pennies Needed for any combo: 4
Tim
It looks like your solution also fails for 25 (it thinks you need a quarter). Since you already have a nickel and two dimes (to be able to make 5 and 20), you don't need a quarter.
Gabe
A: 

In general, if you have your coins COIN[] and your "change range" 1..MAX, the following should find the maximum number of coins.

Initialise array CHANGEVAL[MAX] to -1

For each element coin in COIN:
  set CHANGEVAL[coin] to 1
Until there are no more -1 in CHANGEVAL:
  For each index I over CHANGEVAL:
    if CHANGEVAL[I] != -1:
      let coincount = CHANGEVAL[I]
      For each element coin in COIN:
        let sum = coin + I
        if (COINS[sum]=-1) OR ((coincount+1)<COINS[sum]):
          COINS[sum]=coincount+1

I don't know if the check for coin-minimality in the inner conditional is, strictly speaking, necessary. I would think that the minimal chain of coin-additions would end up being correct, but better safe than sorry.

Vatine
+4  A: 

You need at least 4 pennies, since you want to get 4 as a change, and you can do that only with pennies.

It isn't optimal to have more than 4 pennies. Instead of 4+x pennies, you can have 4 pennies and x nickels - they span at least the same range.

So you have exactly 4 pennies.

You need at least 1 nickel, since you want to get 5 as a change.

It isn't optimal to have more than 1 nickel. Instead of 1+x nickels, you can have 1 nickel and x dimes - they span at least the same range.

So you have exactly 1 nickel.

You need at least 2 dimes, since you want to get 20.

This means you have 4 pennies, 1 nickel and at least 2 dimes.

If you had less than 10 coins, you would have less than 3 quarters. But then the maximal possible change you could get using all coins is 4 + 5 + 20 + 50 = 79, not enough.

This means you have at least 10 coins. Thomas's answer shows that in fact if you have 4 pennies, 1 nickel, 2 dimes and 3 quarters, all is well.

sdcvvc
@sdcwc: while I like the approach, it is not an algorithm, since it only works for the present set of data.
Matthieu M.
Thomas
+7  A: 

What you are looking for is Dynamic Programming.

You don't actually have to enumerate all the possible combinations for every possible values, because you can build it on top of previous answers.

You algorithm need to take 2 parameters:

  • The list of possible coin values, here [1, 5, 10, 25]
  • The range to cover, here [1, 99]

And the goal is to compute the minimal set of coins required for this range.

The simplest way is to proceed in a bottom-up fashion:

Range     Number of coins (in the minimal set)
          1   5   10   25
[1,1]     1
[1,2]     2
[1,3]     3
[1,4]     4
[1,5]     5
[1,5]*    4   1             * two solutions here
[1,6]     4   1
[1,9]     4   1
[1,10]    5   1             * experience tells us it's not the most viable one :p
[1,10]    4   2             * not so viable either
[1,10]    4   1   1
[1,11]    4   1   1
[1,19]    4   1   1
[1,20]    5   1   1         * not viable (in the long run)
[1,20]    4   2   1         * not viable (in the long run)
[1,20]    4   1   2

It is somewhat easy, at each step we can proceed by adding at most one coin, we just need to know where. This boils down to the fact that the range [x,y] is included in [x,y+1] thus the minimal set for [x,y+1] should include the minimal set for [x,y].

As you may have noticed though, sometimes there are indecisions, ie multiple sets have the same number of coins. In this case, it can only be decided later on which one should be discarded.

It should be possible to improve its running time, when noticing that adding a coin usually allows you to cover a far greater range that the one you added it for, I think.

For example, note that:

 [1,5]    4*1  1*5
 [1,9]    4*1  1*5

we add a nickel to cover [1,5] but this gives us up to [1,9] for free!

However, when dealing with outrageous input sets [2,3,5,10,25] to cover [2,99], I am unsure as how to check quickly the range covered by the new set, or it would be actually more efficient.

Matthieu M.
+2  A: 

Nice Question. This is the logic I came up with. Tested with few scenarios including 25.

class Program
{

    //Allowable denominations
    const int penny = 1;
    const int nickel = 5;
    const int dime = 10;
    const int quarter = 25;

    const int maxCurrencyLevelForTest =55; //1-n where n<=99

    static void Main(string[] args)
    {         
        int minPenniesNeeded = 0;
        int minNickelsNeeded = 0; 
        int minDimesNeeded = 0; 
        int minQuartersNeeded = 0;


        if (maxCurrencyLevelForTest == penny)
        {
            minPenniesNeeded = 1;
        }
        else if (maxCurrencyLevelForTest < nickel)
        {
            minPenniesNeeded = MinCountNeeded(penny, maxCurrencyLevelForTest);                
        }
        else if (maxCurrencyLevelForTest < dime)
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, maxCurrencyLevelForTest);                
        }
        else if (maxCurrencyLevelForTest < quarter)
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, dime - 1);
            minDimesNeeded = MinCountNeeded(dime, maxCurrencyLevelForTest);
        }
        else
        {
            minPenniesNeeded = MinCountNeeded(penny, nickel - 1);
            minNickelsNeeded = MinCountNeeded(nickel, dime - 1);
            minDimesNeeded = MinCountNeeded(dime, quarter - 1);

            var maxPossilbleValueWithoutQuarters = (minPenniesNeeded * penny + minNickelsNeeded * nickel + minDimesNeeded * dime);
            if (maxCurrencyLevelForTest > maxPossilbleValueWithoutQuarters)
            {               
                minQuartersNeeded = (((maxCurrencyLevelForTest - maxPossilbleValueWithoutQuarters)-1) / quarter) + 1;
            }
        }


        var minCoinsNeeded = minPenniesNeeded + minNickelsNeeded+minDimesNeeded+minQuartersNeeded;

        Console.WriteLine(String.Format("Min Number of coins needed: {0}", minCoinsNeeded));
        Console.WriteLine(String.Format("Penny: {0} needed", minPenniesNeeded));
        Console.WriteLine(String.Format("Nickels: {0} needed", minNickelsNeeded));
        Console.WriteLine(String.Format("Dimes: {0} needed", minDimesNeeded));
        Console.WriteLine(String.Format("Quarters: {0} needed", minQuartersNeeded));
        Console.ReadLine();
    }

    private static int MinCountNeeded(int denomination, int upperRange)
    {
        int remainder;
        return System.Math.DivRem(upperRange, denomination,out remainder);
    }
}

Some results: When maxCurrencyLevelForTest = 25

Min Number of coins needed: 7
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 0 needed

When maxCurrencyLevelForTest = 99

Min Number of coins needed: 10
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 3 needed

maxCurrencyLevelForTest : 54

Min Number of coins needed: 8
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 1 needed

maxCurrencyLevelForTest : 55

Min Number of coins needed: 9
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 2 needed

maxCurrencyLevelForTest : 79

Min Number of coins needed: 9
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 2 needed

maxCurrencyLevelForTest : 85

Min Number of coins needed: 10
Penny: 4 needed
Nickels: 1 needed
Dimes: 2 needed
Quarters: 3 needed

The code can further be refactored I guess.

SKG
+1  A: 

Edit: As the commenters have noted, I have misinterpreted the question. (The question is very similar to a basic CS problem I see students at the college having to solve...) waves hand This is not the answer you are looking for. That said, while the original answer is wrong, we can use it as a stepping stone to an O(n) solution.

So, take the wrong answer below, which only solves for a single value (ie, the minimum coinage required for 68 cents) and simply run it for every value.

changes = []
for amount in xrange(1, 100): # [1, 99]
    changes.append( run_the_algo_below( amount ) )
# Take the maximum for each coin type.
# ie, if run_the_algo_below returns (q, d, n, p):
change = [0, 0, 0, 0]
for c in changes:
    change = [max(c[i], change[i] for i in xrange(0, 4)]

Now, this will certainly give you a valid answer, but is it a minimal answer? (this is the harder part. Currently my gut says yes, but I'm still thinking about this one...)


(The wrong answer)

Wow. Loops? Dynamic programming? Really folks?

In Python:

amount = ( your_amount_in_cents )

quarters = amount // 25
dimes = amount % 25 // 10
nickels = amount % 25 % 10 // 5
pennies = amount % 25 % 10 % 5

Probably some of those modulo operations can be simplified...

This isn't hard, you just need to think about how you make change in real life. You give out quarters until adding another quarter would put you over the desired amount, you give out dimes until adding another dime would put you over the desired amount, so on. Then, convert to mathematical operations: modulo and division. Same solution applies for dollars, converting seconds into HH:MM:SS, etc.

Thanatos
-1. You've misinterpreted the question..read some of the comments. Your sol'n fails for the suggested input of 99 cents. It says 9Q, 2D, 0N, 4P. How are you going to make 9 cents with 4 pennies and no nickels?
Mark
When the OP says "Find the least number of coins to make any change from 1 to 99", he means a *single* set of coins which has subsets summing to *each* of those values. (And specifically, the smallest such set.)
Tim Goodman
Also requires a code change if the set of available coins changes.
Blrfl
@Mark: You have a calculation error if you got 9Q for an input of 99 using what I posted. `99 // 25` is 3. (Likewise, your dimes, nickels and pennies are off.)
Thanatos
@Mark, @Tim Goodman: Edited - now attempts to solve the right problem, hopefully.
Thanatos
@Blrfl: It can be easily generalized to an arbitrary set of coins.
Thanatos
@Thanatos: Sorry.. I meant 3/2/0/4=9. Why are the dimes and pennies off? I actually ran the program..that's what it says. Redacted the -1 for edit; it wasn't that your answer was wrong, it was the snide comment at the beginning that pushed me over ;)
Mark
Your new sol'n looks like it should work...but I think you can make it more efficient yet by using the dynamic programming ideas that others have suggested.
Mark
@Mark: Heh, I'll let the comment stand for my posterity, to remind me to really understand the problem before I attempt to answer it.
Thanatos
Yes, the hard part is verifying that your answer is correct. Imagine a situation that's not so simple, where you have 10 different coin values and you have to be able to make any value from 1 to 10,000. It's easy to get a "good enough" value, but not so easy to verify that it's indeed the best solution.
Daniel T.
+1  A: 

The task

Find the least number of coins required, that can make any change from 1 to 99 cent.

differs from the task

For each single change from 1 to 99 cent, find the least number of coins required.

because the solution might be a complete different multiset of coins.

Suppose you have not (1), (5), (10), and (25) cent coins, but (1), (3), (5), and (17) cent coins: To make the change for 5, you only need one (5) coin; but for all changes from 1 to 5 you need two (1) coins and one (3) coin, not any (5) coin.

The greedy algorithm iterates from the smallest value to the largest, concerning the change values and coin values:

With 1x(1) you get all change values below 2.

To make a change of 2, you need an additional coin,
which could have any value up to 2;
choose greedy -> choose the largest -> (1).

With 2x(1) you get all change values below 3.

To make a change of 3, you need an additional coin,
which could have any value up to 3;
choose greedy -> choose the largest -> (3).

With 2x(1)+1x(3) you get all change values below 6.

To make a change of 6, you need an additional coin,
which could have any value up to 6;
choose greedy -> choose the largest -> (5).

and so on...

That is in Haskell:

coinsforchange [1,3,5,17] 99
where
    coinsforchange coins change = 
        let f (coinssofar::[Int],sumsofar::Int) (largestcoin::Int,wanttogoto::Int) = 
                let coincount=(max 0 (wanttogoto-sumsofar+largestcoin-1))`div`largestcoin
                 in (replicate coincount largestcoin++coinssofar,sumsofar+coincount*largestcoin)
         in foldl f ([],0) $ zip coins $ tail [c-1|c<-coins] ++ [change]

And in C++:

void f(std::map<unsigned,int> &coinssofar,int &sumsofar, unsigned largestcoin, int wanttogoto)
{
    int x = wanttogoto - sumsofar + largestcoin - 1;
    coinssofar[largestcoin] = (x>0) ? (x / largestcoin) : 0;
    //returns coinssofar and sumsofar;
}
std::map<unsigned,int> coinsforchange(const std::list<unsigned> &coins, int change)
{
    std::map<unsigned,int> coinssofar;
    int sumsofar=0;
    std::list<unsigned>::const_iterator coin = coins.begin();
    unsigned largestcoin = *coin;
    for( ++coin ; coin!=coins.end() ; largestcoin=*(coin++))
        f(coinssofar,sumsofar,largestcoin,(*coin) - 1);
    f(coinssofar,sumsofar,largestcoin,change);
    return coinssofar;
}
comonad
c++ looks uglier than I remembered it.
Mark
yeah, sure. so ...imperative. +1 for that.
comonad
A: 

A vb version

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs) Handles Button1.Click
        For saleAMT As Decimal = 0.01D To 0.99D Step 0.01D
            Dim foo As New CashDrawer(0, 0, 0)
            Dim chg As List(Of Money) = foo.MakeChange(saleAMT, 1D)
            Dim t As Decimal = 1 - saleAMT
            Debug.WriteLine(t.ToString("C2"))
            For Each c As Money In chg
                Debug.WriteLine(String.Format("{0} of {1}", c.Count.ToString("N0"), c.moneyValue.ToString("C2")))
            Next
        Next
    End Sub

    Class CashDrawer

        Private _drawer As List(Of Money)

        Public Sub New(Optional ByVal QTYtwoD As Integer = -1, _
                       Optional ByVal QTYoneD As Integer = -1, _
                       Optional ByVal QTYfifty As Integer = -1, _
                       Optional ByVal QTYquarters As Integer = -1, _
                       Optional ByVal QTYdimes As Integer = -1, _
                       Optional ByVal QTYnickels As Integer = -1, _
                       Optional ByVal QTYpennies As Integer = -1)
            _drawer = New List(Of Money)
            _drawer.Add(New Money(2D, QTYtwoD))
            _drawer.Add(New Money(1D, QTYoneD))
            _drawer.Add(New Money(0.5D, QTYfifty))
            _drawer.Add(New Money(0.25D, QTYquarters))
            _drawer.Add(New Money(0.1D, QTYdimes))
            _drawer.Add(New Money(0.05D, QTYnickels))
            _drawer.Add(New Money(0.01D, QTYpennies))
        End Sub

        Public Function MakeChange(ByVal SaleAmt As Decimal, _
                                   ByVal amountTendered As Decimal) As List(Of Money)
            Dim change As Decimal = amountTendered - SaleAmt
            Dim rv As New List(Of Money)
            For Each c As Money In Me._drawer
                change -= (c.NumberOf(change) * c.moneyValue)
                If c.Count > 0 Then
                    rv.Add(c)
                End If
            Next
            If change <> 0D Then Throw New ArithmeticException
            Return rv
        End Function
    End Class

    Class Money
        '-1 equals unlimited qty
        Private _qty As Decimal 'quantity in drawer
        Private _value As Decimal 'value money
        Private _count As Decimal = 0D

        Public Sub New(ByVal theValue As Decimal, _
                       ByVal theQTY As Decimal)
            Me._value = theValue
            Me._qty = theQTY
        End Sub

        ReadOnly Property moneyValue As Decimal
            Get
                Return Me._value
            End Get
        End Property

        Public Function NumberOf(ByVal theAmount As Decimal) As Decimal
            If (Me._qty > 0 OrElse Me._qty = -1) AndAlso Me._value <= theAmount Then
                Dim ct As Decimal = Math.Floor(theAmount / Me._value)
                If Me._qty <> -1D Then 'qty?
                    'limited qty
                    If ct > Me._qty Then 'enough 
                        'no
                        Me._count = Me._qty
                        Me._qty = 0D
                    Else
                        'yes
                        Me._count = ct
                        Me._qty -= ct
                    End If
                Else
                    'unlimited qty
                    Me._count = ct
                End If
            End If
            Return Me._count
        End Function

        ReadOnly Property Count As Decimal
            Get
                Return Me._count
            End Get
        End Property
    End Class
End Class
dbasnett
A: 

Here's a simple version in Python.

#!/usr/bin/env python

required = []
coins = [25, 10, 5, 1]

t = []
for i in range(1, 100):
    while sum(t) != i:
        for c in coins:
            if sum(t) + c <= i:
                t.append(c)
                break
    for c in coins:
        while t.count(c) > required.count(c):
            required.append(c)
    del t[:]

print required

When run, it prints the following to stdout.

[1, 1, 1, 1, 5, 10, 10, 25, 25, 25]

The code is pretty self-explanatory (thanks Python!), but basically the algorithm is to add the largest coin available that doesn't put you over the current total you're shooting for into your temporary list of coins (t in this case). Once you find the most efficient set of coins for a particular total, make sure there are at least that many of each coin in the required list. Do that for every total from 1 to 99 cents, and you're done.

Zeke