using System; using System.Collections.Generic; using System.Linq; class Program { static int UB; static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); static void Main() { Solve(2); Solve(5); } struct JyoutaiDef { internal int Level; internal int[] BanArr; internal List<int[]> Log; } static void Solve(int pN) { UB = pN * 2 - 1; for (int I = 1; I < int.MaxValue; I++) { if (ExecDFS(pN, I)) break; } } static bool ExecDFS(int pN, int pLevelLimit) { var stk = new Stack<JyoutaiDef>(); JyoutaiDef WillPush; WillPush.Level = 0; WillPush.BanArr = Enumerable.Range(1, pN * 2).ToArray(); WillPush.Log = new List<int[]>() { WillPush.BanArr }; stk.Push(WillPush); var MinTesuuDict = new Dictionary<ulong, int>(); MinTesuuDict.Add(BanToULong(WillPush.BanArr), 0); while (stk.Count > 0) { JyoutaiDef Popped = stk.Pop(); //クリア判定 IEnumerable<int> AnswerEnum = Enumerable.Range(1, pN * 2).Reverse(); if (Popped.BanArr.Cast<int>().SequenceEqual(AnswerEnum)) { Console.WriteLine("N={0}での解を発見。経過時間={1}", pN, sw.Elapsed); for (int I = 0; I <= Popped.Log.Count - 1; I++) { Console.Write("{0}回目 ", I); Array.ForEach(Popped.Log[I], X => Console.Write("{0},", X)); Console.WriteLine(); } return true; } //下限値枝切り int NeedMinTesuu = DeriveNeedMinTesuu(pN, Popped.BanArr); if (pLevelLimit < Popped.Level + NeedMinTesuu) continue; for (int LoopFromInd = 0; LoopFromInd <= UB; LoopFromInd++) { int ToInd = LoopFromInd + pN - 1; if (UB < ToInd) break; int[] CopiedArr = new int[pN]; Array.Copy(Popped.BanArr, LoopFromInd, CopiedArr, 0, pN); var wkList = Popped.BanArr.ToList(); wkList.RemoveRange(LoopFromInd, pN); wkList.InsertRange(0, CopiedArr); WillPush.BanArr = wkList.ToArray(); WillPush.Level = Popped.Level + 1; int MinTesuu; ulong BanULong = BanToULong(WillPush.BanArr); if (MinTesuuDict.TryGetValue(BanULong, out MinTesuu)) { if (MinTesuu <= WillPush.Level) continue; } MinTesuuDict[BanULong] = WillPush.Level; WillPush.Log = new List<int[]>(Popped.Log) { WillPush.BanArr }; stk.Push(WillPush); } } return false; } //必要な最低手数を求める static int DeriveNeedMinTesuu(int pN, int[] pBanArr) { if (pBanArr[UB] == 1) return 1; if (pBanArr[UB - pN] == 1) return 1; return 2; } //盤面をULong型で表現 static ulong BanToULong(int[] pBanArr) { var sb = new System.Text.StringBuilder(); for (int I = 0; I <= UB; I++) { sb.Append(pBanArr[I]); } return ulong.Parse(sb.ToString()); } }
N=2での解を発見。経過時間=00:00:00.0449537 0回目 1,2,3,4, 1回目 2,3,1,4, 2回目 3,1,2,4, 3回目 2,4,3,1, 4回目 4,3,2,1, N=5での解を発見。経過時間=00:05:55.8889062 0回目 1,2,3,4,5,6,7,8,9,10, 1回目 5,6,7,8,9,1,2,3,4,10, 2回目 7,8,9,1,2,5,6,3,4,10, 3回目 9,1,2,5,6,7,8,3,4,10, 4回目 1,2,5,6,7,9,8,3,4,10, 5回目 5,6,7,9,8,1,2,3,4,10, 6回目 7,9,8,1,2,5,6,3,4,10, 7回目 9,8,1,2,5,7,6,3,4,10, 8回目 7,6,3,4,10,9,8,1,2,5, 9回目 4,10,9,8,1,7,6,3,2,5, 10回目 7,6,3,2,5,4,10,9,8,1, 11回目 5,4,10,9,8,7,6,3,2,1, 12回目 10,9,8,7,6,5,4,3,2,1,
反復深化深さ優先探索で解いてます。