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

13-08 ビルディング

問題

受験研究社のビルディングを解きます。





ソース

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

class Program
{
    const int UB = 4 - 1;

    struct JyoutaiDef
    {
        internal int CurrX;
        internal int CurrY;
        internal int[,] BillArr;
    }

    static void Main()
    {
        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.CurrX = WillPush.CurrY = 0;

        for (int I = 1; I <= 4; I++) {
            WillPush.BillArr = new int[UB + 1, UB + 1];
            WillPush.BillArr[0, 0] = I;
            stk.Push(WillPush);
        }

        int AnswerCnt = 0;

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

            //X座標の繰上げ処理
            if (++Popped.CurrX > UB) {
                Popped.CurrX = 0;
                Popped.CurrY++;
            }

            //クリア判定
            if (Popped.CurrY > UB) {
                if (CanSeeBillsCnt(new int[]{Popped.BillArr[3,0],Popped.BillArr[2,0],
                                             Popped.BillArr[1,0],Popped.BillArr[0,0]}) != 2) continue;
                if (CanSeeBillsCnt(new int[]{Popped.BillArr[0,1],Popped.BillArr[1,1],
                                             Popped.BillArr[2,1],Popped.BillArr[3,1]}) != 3) continue;
                if (CanSeeBillsCnt(new int[]{Popped.BillArr[1,3],Popped.BillArr[1,2],
                                             Popped.BillArr[1,1],Popped.BillArr[1,0]}) != 2) continue;
                if (CanSeeBillsCnt(new int[]{Popped.BillArr[3,3],Popped.BillArr[3,2],
                                             Popped.BillArr[3,1],Popped.BillArr[3,0]}) != 3) continue;

                Console.WriteLine("解{0}を発見", ++AnswerCnt);
                PrintAnswer(Popped.BillArr);
                continue;
            }

            for (int I = 1; I <= 4; I++) {
                bool IsUsed = false;

                //横方向で使用してないこと
                for (int X = 0; X <= UB; X++) {
                    if (Popped.BillArr[X, Popped.CurrY] == I) {
                        IsUsed = true;
                        break;
                    }
                }

                //縦方向で使用してないこと
                for (int Y = 0; Y <= UB; Y++) {
                    if (Popped.BillArr[Popped.CurrX, Y] == I) {
                        IsUsed = true;
                        break;
                    }
                }

                if (IsUsed == false) {
                    WillPush.CurrX = Popped.CurrX;
                    WillPush.CurrY = Popped.CurrY;
                    WillPush.BillArr = (int[,])Popped.BillArr.Clone();
                    WillPush.BillArr[Popped.CurrX, Popped.CurrY] = I;
                    stk.Push(WillPush);
                }
            }
        }
    }

    //見えるビルの数を判定
    static int CanSeeBillsCnt(int[] pBillArr)
    {
        int WillReturn = 1;
        int CurrMaxHeight = pBillArr[0];

        //最大値を超えたらインクリメント
        for (int I = 1; I <= UB; I++) {
            if (CurrMaxHeight < pBillArr[I]) {
                CurrMaxHeight = pBillArr[I];
                WillReturn++;
            }
        }
        return WillReturn;
    }

    //解を出力
    static void PrintAnswer(int[,] pBillArr)
    {
        var sb = new System.Text.StringBuilder();
        for (int Y = 0; Y <= UB; Y++) {
            for (int X = 0; X <= UB; X++) {
                sb.Append(pBillArr[X, Y]);
            }
            sb.AppendLine();
        }
        Console.WriteLine(sb.ToString());
    }
}


実行結果

解1を発見
4123
2314
1432
3241

解2を発見
3412
2134
1243
4321

解3を発見
3241
2314
1423
4132

解4を発見
3241
2134
1423
4312

解5を発見
3241
1324
2413
4132

解6を発見
3142
2314
1423
4231

解7を発見
3142
1324
2413
4231

解8を発見
2143
1324
3412
4231

解9を発見
1243
2134
3412
4321


解説

1,2,3,4の組み合わせを列挙しきってから、
解になるかを検証してます。