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

Cマガ電脳クラブ(第082回) ひとふで数環

問題

8マスに分けられた環があり、各マスに1から7までの連続した7数が配置してある (Fig.1)
まず'1'からスタートして、
1マス目に'2'があり、
その'2'から2マス目に'3'があり、
その'3'から3マス目に'4'があり・・・と続き、
最後に'7' (ここでの最大の数) から7マス目に'1'があり、スタート地点に戻る。
このルールに従うと、この8マスの環には1から8までを配置することはできなくて、1から7までが最長である。

ではここで問題。
100マスに分けられた環には、最長1からいくつまで配置できるだろうか。

Fig.1 ひとふで数環


ソース

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

class Program
{
    const int UB = 100 - 1;

    struct JyoutaiDef
    {
        internal int CurrInd;
        internal int[] BanArr;
    }

    static void Main()
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();

        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.CurrInd = 1; //対称解の除外で、固定で右方向に1移動とする
        WillPush.BanArr = new int[UB + 1];
        WillPush.BanArr[0] = 1;
        WillPush.BanArr[1] = 2;
        stk.Push(WillPush);

        int AnswerLength = 0;
        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();
            int CurrNum = Popped.BanArr[Popped.CurrInd];

            //スタート地点に戻れる場合は、解候補
            if (AnswerLength <= CurrNum) {
                List<int> MasuIndList = DeriveMasuIndList(Popped.CurrInd, CurrNum);
                if (MasuIndList.Contains(0)) {
                    AnswerLength = CurrNum;

                    var sb = new System.Text.StringBuilder();
                    sb.AppendLine();
                    sb.AppendFormat("環の長さ{0}の解候補を発見。経過時間={1}", 
                        AnswerLength, sw.Elapsed);
                    sb.AppendLine();
                    for (int I = 0; I <= Popped.BanArr.GetUpperBound(0); I++) {
                        sb.AppendFormat("{0,2} ", Popped.BanArr[I]);
                        if (I % 10 == 9 || I == Popped.BanArr.GetUpperBound(0)) sb.AppendLine();
                    }
                    Console.WriteLine(sb.ToString());
                }
            }

            int[] SpaceMasuIndArr = DeriveSpaceMasuIndArr(Popped.CurrInd, Popped.BanArr);
            foreach (int EachSpaceMasuInd in SpaceMasuIndArr) {
                WillPush.CurrInd = EachSpaceMasuInd;
                WillPush.BanArr = (int[])Popped.BanArr.Clone();
                WillPush.BanArr[EachSpaceMasuInd] = CurrNum + 1;
                stk.Push(WillPush);
            }
        }
        Console.WriteLine("経過時間={0}", sw.Elapsed);
    }

    //左方向もしくは右方向の、指定マス先の空欄のIndの配列を返す
    static int[] DeriveSpaceMasuIndArr(int pCurrInd, int[] pBanArr)
    {
        var WillReturn = new List<int>();

        List<int> MasuIndList = DeriveMasuIndList(pCurrInd, pBanArr[pCurrInd]);
        foreach (int EachMasuInd in MasuIndList) {
            if (pBanArr[EachMasuInd] == 0) WillReturn.Add(EachMasuInd);
        }
        return WillReturn.ToArray();
    }

    //左方向もしくは右方向の、指定マス先のIndのListを返す
    static List<int> DeriveMasuIndList(int pCurrInd, int pMasuCnt)
    {
        var WillReturn = new List<int>();

        //左方向の指定マス先のInd
        int LeftInd = pCurrInd - pMasuCnt;
        if (LeftInd < 0) LeftInd += UB + 1;
        WillReturn.Add(LeftInd);

        //右方向の指定マス先のInd
        int RightInd = pCurrInd + pMasuCnt;
        if (RightInd > UB) RightInd -= UB + 1;
        WillReturn.Add(RightInd);

        if (LeftInd == RightInd) WillReturn.RemoveAt(1);
        return WillReturn;
    }
}


実行結果

省略
環の長さ87の解候補を発見。経過時間=00:00:10.3127403
 1  2  0  3  0  0  4 11  9  7
 5 62 60 58 40  6  8 10  0 67
69 71 28 30 32  0 56 54 52 50
48 46 44 42  0  0  0 74 76 78
80 82 84  0 25 23 21 19  0 63
65 70 68 39 37 35 33  0 85 83
81 79 77 75 73 18 20 22 24 26
57 59 61 86 41 43 45 47 49 51
53 55 17 15 13 66 64 87  0 34
36 38 72 31 29 27 12 14 16  0

経過時間=00:02:06.4052023


解説

深さ優先探索でナイーブに解いてます。