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

8-26 油分け算2 {8,5,3}を{4,4,0}

問題

8リットル入りの容器に油がいっぱい入っており、
他に5リットルと3リットルの容器がある。
これらの容器だけを使って、油を正確に4リットルずつ分けるには
どうすればよいか。

油分け算 : クイズ&パズルの部屋「Quizzical Days.」


ソース

using System;
using System.Collections.Generic;

class Program
{
    struct JyoutaiDef
    {
        internal int Youki8;
        internal int Youki5;
        internal int Youki3;
        internal List<string> Log;
    }

    static void Main()
    {
        var que = new Queue<JyoutaiDef>();
        JyoutaiDef WillEnqueue;
        WillEnqueue.Youki8 = 8;
        WillEnqueue.Youki5 = WillEnqueue.Youki3 = 0;
        WillEnqueue.Log = new List<string>();
        WillEnqueue.Log.Add(MakeOneLog(8, 0, 0));
        que.Enqueue(WillEnqueue);

        int MaxLevel = int.MaxValue;
        int AnswerCnt = 0;
        while (que.Count > 0) {
            JyoutaiDef Dequeued = que.Dequeue();
            if (MaxLevel < Dequeued.Log.Count) continue;

            if (Dequeued.Youki8 == 4 && Dequeued.Youki5 == 4) {
                Console.WriteLine("解{0}を発見しました。", ++AnswerCnt);
                Dequeued.Log.ForEach(X => Console.WriteLine(X));
                if (MaxLevel > Dequeued.Log.Count)
                    MaxLevel = Dequeued.Log.Count;
                continue;
            }

            Action<int, int, int> EnqueSyori = (pYouki8, pYouki5, pYouki3) =>
            {
                WillEnqueue.Youki8 = pYouki8;
                WillEnqueue.Youki5 = pYouki5;
                WillEnqueue.Youki3 = pYouki3;

                string NewLog = MakeOneLog(pYouki8, pYouki5, pYouki3);
                if (Dequeued.Log.Contains(NewLog)) return;

                WillEnqueue.Log = new List<string>(Dequeued.Log);
                WillEnqueue.Log.Add(NewLog);
                que.Enqueue(WillEnqueue);
            };

            if (Dequeued.Youki8 > 0) {
                if (Dequeued.Youki5 < 5) {
                    int Aki = 5 - Dequeued.Youki5;
                    int Fill = Math.Min(Aki, Dequeued.Youki8);
                    EnqueSyori(Dequeued.Youki8 - Fill, Dequeued.Youki5 + Fill, Dequeued.Youki3);
                }
                if (Dequeued.Youki3 < 3) {
                    int Aki = 3 - Dequeued.Youki3;
                    int Fill = Math.Min(Aki, Dequeued.Youki8);
                    EnqueSyori(Dequeued.Youki8 - Fill, Dequeued.Youki5, Dequeued.Youki3 + Fill);
                }
            }
            if (Dequeued.Youki5 > 0) {
                if (Dequeued.Youki8 < 8) {
                    int Aki = 8 - Dequeued.Youki8;
                    int Fill = Math.Min(Aki, Dequeued.Youki5);
                    EnqueSyori(Dequeued.Youki8 + Fill, Dequeued.Youki5 - Fill, Dequeued.Youki3);
                }
                if (Dequeued.Youki3 < 3) {
                    int Aki = 3 - Dequeued.Youki3;
                    int Fill = Math.Min(Aki, Dequeued.Youki5);
                    EnqueSyori(Dequeued.Youki8, Dequeued.Youki5 - Fill, Dequeued.Youki3 + Fill);
                }
            }
            if (Dequeued.Youki3 > 0) {
                if (Dequeued.Youki8 < 8) {
                    int Aki = 8 - Dequeued.Youki8;
                    int Fill = Math.Min(Aki, Dequeued.Youki3);
                    EnqueSyori(Dequeued.Youki8 + Fill, Dequeued.Youki5, Dequeued.Youki3 - Fill);
                }
                if (Dequeued.Youki5 < 5) {
                    int Aki = 5 - Dequeued.Youki5;
                    int Fill = Math.Min(Aki, Dequeued.Youki3);
                    EnqueSyori(Dequeued.Youki8, Dequeued.Youki5 + Fill, Dequeued.Youki3 - Fill);
                }
            }
        }
    }

    static string MakeOneLog(int pYouki8, int pYouki5, int pYouki3)
    {
        return string.Format("容器8={0},容器5={1},容器3={2}", pYouki8, pYouki5, pYouki3);
    }
}


実行結果

解1を発見しました。
容器8=8,容器5=0,容器3=0
容器8=3,容器5=5,容器3=0
容器8=3,容器5=2,容器3=3
容器8=6,容器5=2,容器3=0
容器8=6,容器5=0,容器3=2
容器8=1,容器5=5,容器3=2
容器8=1,容器5=4,容器3=3
容器8=4,容器5=4,容器3=0


解説

Actionデリゲートで共通処理をまとめてます。