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
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 &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 coinsforchange(const std::list &coins, int change)
{
std::map coinssofar;
int sumsofar=0;
std::list::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;
}