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

8-33 川渡り問題4 猛獣親子の川渡り

問題



トラ・ライオン・ヒョウの3組の親子が、舟で川を渡ろうとしている。
舟は1艘(そう)しかないが、1度に2匹まで乗ることができ、
またどの動物も舟を漕(こ)ぐことが可能である。

ただし、親子同士でない成獣(親)と幼獣(子)が同じ場所におり、
かつその子の親が近くにいない場合、子は食べられてしまう。

さて、全員が無事に川を渡り切るにはどうすればよいだろうか?

猛獣親子の川渡り : クイズ&パズルの部屋「Quizzical Days.」


ソース

using System;
using System.Collections.Generic;

class Program
{
    struct JyoutaiDef
    {
        internal int Level;
        internal bool IsToraOyaLeft;
        internal bool IsToraKoLeft;
        internal bool IsLionOyaLeft;
        internal bool IsLionKoLeft;
        internal bool IsHyouOyaLeft;
        internal bool IsHyouKoLeft;
        internal bool IsIkadaLeft;
        internal List<string> LogList;

        internal void Init()
        {
            Level = 0;
            IsToraOyaLeft = IsToraKoLeft = true;
            IsLionOyaLeft = IsLionKoLeft = true;
            IsHyouOyaLeft = IsHyouKoLeft = true;
            IsIkadaLeft = true;
            LogList = new List<string>();
            AddOneLog();
        }

        internal void MakeKishiInfo(bool pIsLeftInfo, System.Text.StringBuilder pSb)
        {
            if (pIsLeftInfo == IsToraOyaLeft) pSb.Append("親トラ,");
            if (pIsLeftInfo == IsToraKoLeft) pSb.Append("子トラ,");
            if (pIsLeftInfo == IsLionOyaLeft) pSb.Append("親ライオン,");
            if (pIsLeftInfo == IsLionKoLeft) pSb.Append("子ライオン,");
            if (pIsLeftInfo == IsHyouOyaLeft) pSb.Append("親ヒョウ,");
            if (pIsLeftInfo == IsHyouKoLeft) pSb.Append("子ヒョウ,");
        }

        internal bool AddOneLog()
        {
            var sb = new System.Text.StringBuilder();
            MakeKishiInfo(true, sb);
            sb.Append(IsIkadaLeft ? " 筏 川川川 " : " 川川川 筏 ");
            MakeKishiInfo(false, sb);

            string wkStr = sb.ToString();
            if (LogList.Contains(wkStr)) return false;
            LogList.Add(wkStr);
            return true;
        }

        internal void PrintLog()
        {
            for (int I = 0; I <= LogList.Count - 1; I++)
                Console.WriteLine("レベル{0,2} {1}", I, LogList[I]);
        }

        internal bool IsValid()
        {
            if (IsToraOyaLeft != IsToraKoLeft &&
               (IsToraKoLeft == IsLionOyaLeft || IsToraKoLeft == IsHyouOyaLeft)) return false;
            if (IsLionOyaLeft != IsLionKoLeft &&
               (IsLionKoLeft == IsToraOyaLeft || IsLionKoLeft == IsHyouOyaLeft)) return false;
            if (IsHyouOyaLeft != IsHyouKoLeft &&
               (IsHyouKoLeft == IsToraOyaLeft || IsHyouKoLeft == IsLionOyaLeft)) return false;
            return true;
        }
    }

    static void Main()
    {
        var Jyoutai = new JyoutaiDef();
        Jyoutai.Init();

        var que = new Queue<JyoutaiDef>();
        que.Enqueue(Jyoutai);

        int AnswerLevel = int.MaxValue;
        int AnswerCnt = 0;
        while (que.Count != 0) {
            Jyoutai = que.Dequeue();
            //Jyoutai.PrintLog();
            if (++Jyoutai.Level > AnswerLevel) continue;

            if (Jyoutai.IsToraOyaLeft == false && Jyoutai.IsToraKoLeft == false
             && Jyoutai.IsLionOyaLeft == false && Jyoutai.IsLionKoLeft == false
             && Jyoutai.IsHyouOyaLeft == false && Jyoutai.IsHyouKoLeft == false
             && Jyoutai.IsIkadaLeft == false) {
                Console.WriteLine("解{0}を発見しました。", ++AnswerCnt);
                Jyoutai.PrintLog();
                AnswerLevel = Jyoutai.Level;
                continue;
            }

            Action<JyoutaiDef> EnqueueSyori = (pWillEnqueue) =>
            {
                pWillEnqueue.LogList = new List<string>(Jyoutai.LogList);
                pWillEnqueue.IsIkadaLeft = !Jyoutai.IsIkadaLeft;
                if (pWillEnqueue.AddOneLog() && pWillEnqueue.IsValid())
                    que.Enqueue(pWillEnqueue);
            };

            if (Jyoutai.IsIkadaLeft) {
                //親トラと親ライオンで移動
                if (Jyoutai.IsToraOyaLeft && Jyoutai.IsLionOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsLionOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親トラと親ヒョウで移動
                if (Jyoutai.IsToraOyaLeft && Jyoutai.IsHyouOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsHyouOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンと親ヒョウで移動
                if (Jyoutai.IsLionOyaLeft && Jyoutai.IsHyouOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = WillEnqueue.IsHyouOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }

                //親トラで移動
                if (Jyoutai.IsToraOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンで移動
                if (Jyoutai.IsLionOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親ヒョウで移動
                if (Jyoutai.IsHyouOyaLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouOyaLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親トラと子トラで移動
                if (Jyoutai.IsToraOyaLeft && Jyoutai.IsToraKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsToraKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンと子ライオンで移動
                if (Jyoutai.IsLionOyaLeft && Jyoutai.IsLionKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = WillEnqueue.IsLionKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //親ヒョウと子ヒョウで移動
                if (Jyoutai.IsHyouOyaLeft && Jyoutai.IsHyouKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouOyaLeft = WillEnqueue.IsHyouKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラと子ライオンで移動
                if (Jyoutai.IsToraKoLeft && Jyoutai.IsLionKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = WillEnqueue.IsLionKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラと子ヒョウで移動
                if (Jyoutai.IsToraKoLeft && Jyoutai.IsHyouKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = WillEnqueue.IsHyouKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子ライオンと子ヒョウで移動
                if (Jyoutai.IsLionKoLeft && Jyoutai.IsHyouKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionKoLeft = WillEnqueue.IsHyouKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラで移動
                if (Jyoutai.IsToraKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子ライオンで移動
                if (Jyoutai.IsLionKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
                //子ヒョウで移動
                if (Jyoutai.IsHyouKoLeft) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouKoLeft = false;
                    EnqueueSyori(WillEnqueue);
                }
            }
            else {
                //親トラと親ライオンで移動
                if (Jyoutai.IsToraOyaLeft == false && Jyoutai.IsLionOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsLionOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親トラと親ヒョウで移動
                if (Jyoutai.IsToraOyaLeft == false && Jyoutai.IsHyouOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsHyouOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンと親ヒョウで移動
                if (Jyoutai.IsLionOyaLeft == false && Jyoutai.IsHyouOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = WillEnqueue.IsHyouOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親トラで移動
                if (Jyoutai.IsToraOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンで移動
                if (Jyoutai.IsLionOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親ヒョウで移動
                if (Jyoutai.IsHyouOyaLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouOyaLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親トラと子トラで移動
                if (Jyoutai.IsToraOyaLeft == false && Jyoutai.IsToraKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraOyaLeft = WillEnqueue.IsToraKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親ライオンと子ライオンで移動
                if (Jyoutai.IsLionOyaLeft == false && Jyoutai.IsLionKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionOyaLeft = WillEnqueue.IsLionKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //親ヒョウと子ヒョウで移動
                if (Jyoutai.IsHyouOyaLeft == false && Jyoutai.IsHyouKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouOyaLeft = WillEnqueue.IsHyouKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラと子ライオンで移動
                if (Jyoutai.IsToraKoLeft == false && Jyoutai.IsLionKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = WillEnqueue.IsLionKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラと子ヒョウで移動
                if (Jyoutai.IsToraKoLeft == false && Jyoutai.IsHyouKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = WillEnqueue.IsHyouKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子ライオンと子ヒョウで移動
                if (Jyoutai.IsLionKoLeft == false && Jyoutai.IsHyouKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionKoLeft = WillEnqueue.IsHyouKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子トラで移動
                if (Jyoutai.IsToraKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsToraKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子ライオンで移動
                if (Jyoutai.IsLionKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsLionKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
                //子ヒョウで移動
                if (Jyoutai.IsHyouKoLeft == false) {
                    JyoutaiDef WillEnqueue = Jyoutai;
                    WillEnqueue.IsHyouKoLeft = true;
                    EnqueueSyori(WillEnqueue);
                }
            }
        }
    }
}


実行結果

省略
解486を発見しました。
レベル 0 親トラ,子トラ,親ライオン,子ライオン,親ヒョウ,子ヒョウ, 筏 川川川
レベル 1 親トラ,子トラ,親ライオン,親ヒョウ, 川川川 筏 子ライオン,子ヒョウ,
レベル 2 親トラ,子トラ,親ライオン,親ヒョウ,子ヒョウ, 筏 川川川 子ライオン,
レベル 3 親トラ,親ライオン,親ヒョウ, 川川川 筏 子トラ,子ライオン,子ヒョウ,
レベル 4 親トラ,親ライオン,親ヒョウ,子ヒョウ, 筏 川川川 子トラ,子ライオン,
レベル 5 親ヒョウ,子ヒョウ, 川川川 筏 親トラ,子トラ,親ライオン,子ライオン,
レベル 6 親ライオン,子ライオン,親ヒョウ,子ヒョウ, 筏 川川川 親トラ,子トラ,
レベル 7 子ライオン,子ヒョウ, 川川川 筏 親トラ,子トラ,親ライオン,親ヒョウ,
レベル 8 子トラ,子ライオン,子ヒョウ, 筏 川川川 親トラ,親ライオン,親ヒョウ,
レベル 9 子トラ, 川川川 筏 親トラ,親ライオン,子ライオン,親ヒョウ,子ヒョウ,
レベル10 子トラ,子ヒョウ, 筏 川川川 親トラ,親ライオン,子ライオン,親ヒョウ,
レベル11  川川川 筏 親トラ,子トラ,親ライオン,子ライオン,親ヒョウ,子ヒョウ,


解説

幅優先探索で解いてます。