using System; using System.Collections.Generic; using System.Linq; class Program { static void Main(string[] args) { double targetWeight = 23.7; Array.ForEach(Coin.Coins, x => Console.Write((x.Value + "yen").PadLeft(6))); Console.WriteLine(" : Total Amount"); Console.WriteLine(new string('-', 52)); var combinations = CoinCombination.GetGramMatched(targetWeight); int count = 0; foreach (var c in combinations) { foreach (var coin in Coin.Coins) Console.Write(c.GetCount(coin).ToString().PadLeft(6)); Console.WriteLine(" : " + c.Value.ToString().PadLeft(12)); count++; } Console.WriteLine(new string('-', 52)); Console.WriteLine("Target Weight(Gram): " + targetWeight); Console.WriteLine("Number of Combinations: " + count); Console.ReadLine(); } } public struct Coin { public int Value { get; private set; } public double Gram { get; set; } // Gramの有効数字(小数点以下の桁数) public const int GramDecimals = 1; // 全硬貨のリスト(金額が小さい順) public static readonly Coin[] Coins = new[] { new Coin(1, 1), new Coin(5, 3.7), new Coin(10, 4.5), new Coin(50, 4.0), new Coin(100, 4.8), new Coin(500, 7) }; public static readonly Coin Cheapest = Coins[0]; public static readonly Coin Heaviest = Coins[5]; public static readonly Coin Lightest = Coins[0]; private Coin(int val, double gram) : this() { Value = val; Gram = Math.Round(gram, GramDecimals); } // 額面が同額以上のコインを返す public Coin[] GetMoreExpensiveOrEqual() { int index = Array.IndexOf(Coins, this); return Coins.Skip(index).ToArray(); } } public class CoinCombination { public IEnumerable Coins { get; private set; } public double Gram { get; private set; } private int mValue = 0; public int Value { get { if (mValue == 0) mValue = Coins.Sum((x) => x.Value); return mValue; } } public CoinCombination(IEnumerable coins) { this.Coins = coins; Gram = Math.Round(Coins.Sum((x) => x.Gram), Coin.GramDecimals); } private CoinCombination Prepend(Coin coin) { return new CoinCombination(new[]{coin}.Concat(Coins)); } private static IEnumerable GetCombinations(int combinationSize, Coin cheapest) { if(combinationSize == 1) { return cheapest.GetMoreExpensiveOrEqual().Select((x) => new CoinCombination(new[] { x })); } else { return cheapest.GetMoreExpensiveOrEqual().SelectMany((x) => GetCombinations(combinationSize - 1, x), (x, y) => y.Prepend(x)); } } private static IEnumerable GetCombinations(int combinationSize) { return GetCombinations(combinationSize, Coin.Cheapest); } public static IEnumerable GetGramMatched(double gram) { int minCombinationSize = (int)(gram / Coin.Heaviest.Gram); var minCombination = new CoinCombination(Enumerable.Repeat(Coin.Heaviest, minCombinationSize)); if (gram == minCombination.Gram) yield return minCombination; int maxCombinationSize = (int)(gram / Coin.Lightest.Gram); for (int i = minCombinationSize + 1; i < maxCombinationSize; i++) foreach (var item in GetCombinations(i)) if(gram == item.Gram) yield return item; var maxCombination = new CoinCombination(Enumerable.Repeat(Coin.Lightest, maxCombinationSize)); if (gram == maxCombination.Gram) yield return maxCombination; } public int GetCount(Coin coin) { return Coins.Count(x => x.Value == coin.Value); } }