fork download
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4.  
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. double targetWeight = 23.7;
  10. var combinations = CoinCombination.GetCombinations(targetWeight);
  11.  
  12. Console.WriteLine("Target Weight(Gram): " + targetWeight);
  13. Console.WriteLine("Number of Combinations: " + combinations.Count);
  14.  
  15. Array.ForEach(Coin.Coins, x => Console.Write((x.Value + "yen").PadLeft(7)));
  16. Console.WriteLine(" : Total Amount");
  17. Console.WriteLine(new string('-', 58));
  18.  
  19. foreach (var c in combinations)
  20. {
  21. foreach (var coin in Coin.Coins)
  22. Console.Write(c.GetCount(coin).ToString().PadLeft(7));
  23. Console.WriteLine(" : " + c.Value.ToString().PadLeft(12));
  24. }
  25. }
  26. }
  27.  
  28. public struct Coin
  29. {
  30. public int Value { get; private set; }
  31. public double Gram { get; private set; }
  32.  
  33. // Gramの有効数字(小数点以下の桁数)
  34. public const int GramDecimals = 1;
  35.  
  36. // 全硬貨のリスト(金額が小さい順)
  37. public static readonly Coin[] Coins
  38. = new[] { new Coin(1, 1), new Coin(5, 3.7), new Coin(10, 4.5),
  39. new Coin(50, 4.0), new Coin(100, 4.8), new Coin(500, 7) };
  40.  
  41. private Coin(int val, double gram) : this()
  42. {
  43. Value = val;
  44. Gram = Math.Round(gram, GramDecimals);
  45. }
  46.  
  47. // 額面が同額以上のコインを返す
  48. public IEnumerable<Coin> GetMoreExpensiveOrEqual()
  49. {
  50. int index = Array.IndexOf(Coins, this);
  51. return Coins.Skip(index);
  52. }
  53. }
  54.  
  55. public class CoinCombination
  56. {
  57. public List<Coin> Coins { get; private set; }
  58.  
  59. // この組み合わせの中の最高額の硬貨。(GetExpandeds参照)
  60. public Coin MostExpensive
  61. {
  62. get { return Coins[Coins.Count - 1]; }
  63. }
  64.  
  65. private double mGram;
  66. public double Gram
  67. {
  68. get { return mGram; }
  69. private set { mGram = Math.Round(value, Coin.GramDecimals); }
  70. }
  71.  
  72. private int mValue = 0;
  73. public int Value
  74. {
  75. get
  76. {
  77. if (mValue == 0) mValue = Coins.Sum((x) => x.Value);
  78. return mValue;
  79. }
  80. }
  81.  
  82. private CoinCombination() { Coins = new List<Coin>(); }
  83.  
  84. public CoinCombination(params Coin[] coins) :this()
  85. {
  86. Coins.AddRange(coins);
  87. Gram = Coins.Sum(x => x.Gram);
  88. }
  89.  
  90. // コインを一つ追加したCoinCombinationのリストを返す。
  91. // MostExpensiveより額面が小さいコインは追加しない。追加後のGramがmaxGramを超えるCoinCombinationは戻り値に含めない。
  92. private List<CoinCombination> GetExpandeds(double maxGram)
  93. {
  94. var ret = new List<CoinCombination>();
  95. foreach (var coin in MostExpensive.GetMoreExpensiveOrEqual())
  96. {
  97. var expanded = new CoinCombination() { Gram = this.Gram + coin.Gram };
  98. if(expanded.Gram <= maxGram)
  99. {
  100. expanded.Coins.AddRange(this.Coins); expanded.Coins.Add(coin);
  101. ret.Add(expanded);
  102. }
  103. }
  104. return ret;
  105. }
  106.  
  107. // combinationsの要素とそれらに再帰的にコインを追加したものから
  108. // Gramの値がtargetGramに一致するものを検索しリストにして返す。
  109. private static List<CoinCombination> GetCombinations(double targetGram, IEnumerable<CoinCombination> combinations)
  110. {
  111. var ret = new List<CoinCombination>();
  112. foreach (var c in combinations)
  113. {
  114. if (c.Gram == targetGram)
  115. ret.Add(c);
  116. else
  117. ret.AddRange(GetCombinations(targetGram, c.GetExpandeds(targetGram)));
  118. }
  119. return ret;
  120. }
  121.  
  122. public static List<CoinCombination> GetCombinations(double targetGram)
  123. {
  124. return GetCombinations(targetGram, Coin.Coins.Select(x => new CoinCombination(x)));
  125. }
  126.  
  127. public int GetCount(Coin coin)
  128. {
  129. return Coins.Count(x => x.Value == coin.Value);
  130. }
  131. }
Success #stdin #stdout 0.05s 24368KB
stdin
Standard input is empty
stdout
Target Weight(Gram): 23.7
Number of Combinations: 23
   1yen   5yen  10yen  50yen 100yen 500yen : Total Amount
----------------------------------------------------------
     20      1      0      0      0      0 :           25
     16      1      0      1      0      0 :           71
     13      1      0      0      0      1 :          518
     12      1      0      2      0      0 :          117
     11      1      2      0      0      0 :           36
      9      1      0      1      0      1 :          564
      8      1      0      3      0      0 :          163
      7      2      1      0      1      0 :          127
      7      1      2      1      0      0 :           82
      6      1      0      0      0      2 :         1011
      5      1      0      2      0      1 :          610
      4      1      2      0      0      1 :          529
      4      1      0      4      0      0 :          209
      3      3      0      0      2      0 :          218
      3      2      1      1      1      0 :          173
      3      1      2      2      0      0 :          128
      2      1      4      0      0      0 :           47
      2      1      0      1      0      2 :         1057
      1      1      0      3      0      1 :          656
      0      2      1      0      1      1 :          620
      0      1      2      1      0      1 :          575
      0      1      0      5      0      0 :          255
      0      0      1      0      4      0 :          410