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

8-28 油分け算4 平等な乾杯

問題



ある日、3人の友人同士がパーティーに集まった。
彼女らの前にはちょうど12パイントのワインが入った容器があり、
これを正確に4パイントずつ3等分したいと考えている。

しかし、あいにく彼女らは5パイントと3パイント入りのジョッキしか持ち合わせていない。

全員が平等に4パイントずつ飲むにはどうすればよいか。

平等な乾杯 : クイズ&パズルの部屋「Quizzical Days.」


ソース

using System;
using System.Collections.Generic;

class Program
{
    struct JyoutaiDef
    {
        internal int Youki12;
        internal int Youki05;
        internal int Youki03;
        internal int[] NondaRyouArr;
        internal List<string> Log;
    }

    static void Main()
    {
        var que = new Queue<JyoutaiDef>();
        JyoutaiDef WillEnqueue;
        WillEnqueue.Youki12 = 12;
        WillEnqueue.Youki05 = WillEnqueue.Youki03 = 0;
        WillEnqueue.NondaRyouArr = new int[3];
        WillEnqueue.Log = new List<string>();
        WillEnqueue.Log.Add(MakeOneLog(12, 0, 0, WillEnqueue.NondaRyouArr));
        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 (Array.TrueForAll(Dequeued.NondaRyouArr, X => X == 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, int[]> Enq1 = (pYouki12, pYouki05, pYouki03, pNondaRyouArr) =>
            {
                WillEnqueue.Youki12 = pYouki12;
                WillEnqueue.Youki05 = pYouki05;
                WillEnqueue.Youki03 = pYouki03;
                WillEnqueue.NondaRyouArr = pNondaRyouArr;

                string NewLog = MakeOneLog(pYouki12, pYouki05, pYouki03, pNondaRyouArr);
                if (Dequeued.Log.Contains(NewLog)) return;

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

            Action<int, int, int> Enq2 = (pYouki12, pYouki05, pYouki03) =>
            {
                Enq1(pYouki12, pYouki05, pYouki03, Dequeued.NondaRyouArr);
            };

            if (Dequeued.Youki12 > 0) {
                if (Dequeued.Youki05 < 5) {
                    int Aki = 5 - Dequeued.Youki05;
                    int Fill = Math.Min(Aki, Dequeued.Youki12);
                    Enq2(Dequeued.Youki12 - Fill, Dequeued.Youki05 + Fill, Dequeued.Youki03);
                }
                if (Dequeued.Youki03 < 3) {
                    int Aki = 3 - Dequeued.Youki03;
                    int Fill = Math.Min(Aki, Dequeued.Youki12);
                    Enq2(Dequeued.Youki12 - Fill, Dequeued.Youki05, Dequeued.Youki03 + Fill);
                }
            }
            if (Dequeued.Youki05 > 0) {
                if (Dequeued.Youki12 < 12) {
                    int Aki = 12 - Dequeued.Youki12;
                    int Fill = Math.Min(Aki, Dequeued.Youki05);
                    Enq2(Dequeued.Youki12 + Fill, Dequeued.Youki05 - Fill, Dequeued.Youki03);
                }
                if (Dequeued.Youki03 < 3) {
                    int Aki = 3 - Dequeued.Youki03;
                    int Fill = Math.Min(Aki, Dequeued.Youki05);
                    Enq2(Dequeued.Youki12, Dequeued.Youki05 - Fill, Dequeued.Youki03 + Fill);
                }
            }
            if (Dequeued.Youki03 > 0) {
                if (Dequeued.Youki12 < 12) {
                    int Aki = 12 - Dequeued.Youki12;
                    int Fill = Math.Min(Aki, Dequeued.Youki03);
                    Enq2(Dequeued.Youki12 + Fill, Dequeued.Youki05, Dequeued.Youki03 - Fill);
                }
                if (Dequeued.Youki05 < 5) {
                    int Aki = 5 - Dequeued.Youki05;
                    int Fill = Math.Min(Aki, Dequeued.Youki03);
                    Enq2(Dequeued.Youki12, Dequeued.Youki05 + Fill, Dequeued.Youki03 - Fill);
                }
            }

            List<int> NomuKouhoIndList = DeriveNomuKouhoIndList(Dequeued.NondaRyouArr);
            if (1 <= Dequeued.Youki12 && Dequeued.Youki12 <= 4) {
                foreach (int EachInd in NomuKouhoIndList) {
                    if (Dequeued.NondaRyouArr[EachInd] + Dequeued.Youki12 > 4)
                        continue;
                    int[] WillEnQueueArr = (int[])Dequeued.NondaRyouArr.Clone();
                    WillEnQueueArr[EachInd] += Dequeued.Youki12;
                    Enq1(0, Dequeued.Youki05, Dequeued.Youki03, WillEnQueueArr);
                }
            }
            if (1 <= Dequeued.Youki05 && Dequeued.Youki05 <= 4) {
                foreach (int EachInd in NomuKouhoIndList) {
                    if (Dequeued.NondaRyouArr[EachInd] + Dequeued.Youki05 > 4) continue;
                    int[] WillEnQueueArr = (int[])Dequeued.NondaRyouArr.Clone();
                    WillEnQueueArr[EachInd] += Dequeued.Youki05;
                    Enq1(Dequeued.Youki12, 0, Dequeued.Youki03, WillEnQueueArr);
                }
            }
            if (1 <= Dequeued.Youki03 && Dequeued.Youki03 <= 4) {
                foreach (int EachInd in NomuKouhoIndList) {
                    if (Dequeued.NondaRyouArr[EachInd] + Dequeued.Youki03 > 4) continue;
                    int[] WillEnQueueArr = (int[])Dequeued.NondaRyouArr.Clone();
                    WillEnQueueArr[EachInd] += Dequeued.Youki03;
                    Enq1(Dequeued.Youki12, Dequeued.Youki05, 0, WillEnQueueArr);
                }
            }
        }
    }

    static List<int> DeriveNomuKouhoIndList(int[] pNondaRyouArr)
    {
        var WillReturnList = new List<int>();
        for (int I = 0; I <= pNondaRyouArr.GetUpperBound(0); I++) {
            if (pNondaRyouArr[I] == 4) continue;
            if (I >= 1 && pNondaRyouArr[I] == pNondaRyouArr[I - 1])
                continue;

            WillReturnList.Add(I);
        }
        return WillReturnList;
    }

    static string MakeOneLog(int pYouki12, int pYouki05, int pYouki03, int[] pNondaRyouArr)
    {
        var sb = new System.Text.StringBuilder();
        sb.AppendFormat("容器12={0,2},容器5={1},容器3={2},", pYouki12, pYouki05, pYouki03);
        sb.Append("飲んだ量={");
        Array.ForEach(pNondaRyouArr, X => sb.AppendFormat("{0},", X));
        sb.Append("}");
        return sb.ToString();
    }
}


実行結果

省略
解12を発見しました。
容器12=12,容器5=0,容器3=0,飲んだ量={0,0,0,}
容器12= 7,容器5=5,容器3=0,飲んだ量={0,0,0,}
容器12= 7,容器5=2,容器3=3,飲んだ量={0,0,0,}
容器12= 7,容器5=0,容器3=3,飲んだ量={2,0,0,}
容器12= 7,容器5=3,容器3=0,飲んだ量={2,0,0,}
容器12= 4,容器5=3,容器3=3,飲んだ量={2,0,0,}
容器12= 0,容器5=3,容器3=3,飲んだ量={2,4,0,}
容器12= 0,容器5=5,容器3=1,飲んだ量={2,4,0,}
容器12= 0,容器5=5,容器3=0,飲んだ量={2,4,1,}
容器12= 0,容器5=2,容器3=3,飲んだ量={2,4,1,}
容器12= 0,容器5=2,容器3=0,飲んだ量={2,4,4,}
容器12= 0,容器5=0,容器3=0,飲んだ量={4,4,4,}


解説

Array.TrueForAllメソッドで、終了条件を満たしたかをチェックしてます。
MSDN --- Array.TrueForAll<T>メソッド

引数違いの2つのActionデリゲートで、省略引数もどきを実装してます。