public static uint CountWaysToMakeChange(this Money money, params Denomination[] denominations) { Positive.Amounts.AssertArgument(nameof(money), money.Amount); Guard.AgainstNullArgument(nameof(denominations), denominations); long n = money.MinorIntegralAmount; int m = denominations.Length; Currency operationCurrency = money.GetCurrency(); long[] integralDenominations = denominations .Select(d => IntegralDenomination.CalculateAmount(d, operationCurrency)) .ToArray(); // table[i] will be storing the number of solutions for value i. // n+1 rows are needed since the table is constructed in bottom up manner using the base case (n = 0) uint[] table = new uint[n + 1]; // Base case (If given value is 0) table[0] = 1u; // Pick all denominations one by one and update the table[] values after the index // greater than or equal to the value of the picked coin for (int i = 0; i < m; i++) { for (long j = integralDenominations[i]; j <= n; j++) { table[j] += table[j - integralDenominations[i]]; } } return(table[n]); }
internal OptimalChangeSolution(long toChange, Currency operationCurrency, ushort[] table, IntegralDenomination?[] usedDenominations) { _denominations = new QuantifiedDenomination[0]; ushort possibleSolution = table.Last(); if (possibleSolution != ushort.MaxValue) { // at most as many denominations as used List <Denomination> denominations = new List <Denomination>(usedDenominations.Length); IntegralDenomination defaultDenomination = IntegralDenomination.Default(operationCurrency); long denomination = toChange; while (denomination > 0) { IntegralDenomination usedDenomination = usedDenominations[denomination] .GetValueOrDefault(defaultDenomination); denominations.Add(usedDenomination.Denomination); denomination -= usedDenomination.IntegralAmount; } _denominations = QuantifiedDenomination.Aggregate(denominations.OrderByDescending(d => d.Value)) .ToArray(); } }