トップページに戻る    次のC#のサンプルへ    前のC#のサンプルへ

Cマガ電脳クラブ(第014回) くずしてください!

問題

千円札を硬貨に両替することを考える。
たとえば、2枚の硬貨に両替するには、1通りの方法 (500円×2枚) しかないが、11枚だと3通りの方法がある。
 ・100円玉×9枚と50円玉×2枚
 ・500円玉×1枚と50円玉×10枚
 ・500円玉×1枚と100円玉×4枚と50円玉×1枚と10円玉×5枚
もちろん、絶対に両替できない枚数もある (例:3枚) 。Table1に2〜11枚の両替方法の数を示す。

ではここで問題。「千円札をn枚の高価に両替するには、m通りの方法がある」とした場合に、
mが最大になるのはnがいくつのときだろうか。

現在の日本で一般に流通している硬貨は、500円玉、100円玉、50円玉、10円玉、5円玉、1円玉である。念のため。



ソース

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

class Program
{
    struct JyoutaiDef
    {
        internal int CurrP;
        internal int Maisuu;
        internal int SumYen;
        internal string Keiro;
    }

    static void Main()
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;

        int[] CoinArr = { 1, 5, 10, 50, 100, 500 };

        for (int P = 0; P <= CoinArr.GetUpperBound(0); P++) {
            WillPush.CurrP = P;
            WillPush.Maisuu = 1;
            WillPush.SumYen = CoinArr[P];
            WillPush.Keiro = CoinArr[P].ToString() + ",";
            stk.Push(WillPush);
        }

        var ResultDict = new Dictionary<int, int>();
        int CombiCnt = 0;

        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();

            if (Popped.SumYen == 1000) {
                if (++CombiCnt <= 15) { //最初の15個のみを表示
                    Console.WriteLine("1000円になる{0}個目の組み合わせを発見。{1}",
                        CombiCnt, Popped.Keiro);
                }

                if (ResultDict.ContainsKey(Popped.Maisuu))
                    ResultDict[Popped.Maisuu]++;
                else ResultDict[Popped.Maisuu] = 1;

                continue;
            }

            for (int P = Popped.CurrP; P <= CoinArr.GetUpperBound(0); P++) {
                WillPush.CurrP = P;
                WillPush.Maisuu = Popped.Maisuu + 1;
                WillPush.SumYen = Popped.SumYen + CoinArr[P];
                if (WillPush.SumYen > 1000) break;
                WillPush.Keiro = Popped.Keiro + CoinArr[P].ToString() + ",";
                stk.Push(WillPush);
            }
        }

        foreach (var AnyPair in ResultDict.OrderBy(X => X.Value).ThenBy(X => X.Key)) {
            Console.WriteLine("{0}枚に両替する方法は{1}通り", AnyPair.Key, AnyPair.Value);
        }
        Console.WriteLine("経過時間={0}", sw.Elapsed);
    }
}


実行結果

省略
142枚に両替する方法は788通り
152枚に両替する方法は788通り
143枚に両替する方法は789通り
151枚に両替する方法は789通り
147枚に両替する方法は790通り
経過時間=00:01:30.6645283


解説

枚数ごとの組み合わせの数を、Dictionaryジェネリックで管理してます。