using System; using System.Collections.Generic; using System.Linq; class Program { static int UB; static void Main() { //Solve(4, 100); //Solve(6, 100); Solve(8, 100); } struct JyoutaiDef { internal int[] BanArr; internal int Level; internal int OniNum; internal int OniInd; internal int SumKyori; internal List<string> Log; } static void Solve(int pN, int pLimitSumKyori) { UB = pN - 1; var stk = new Stack<JyoutaiDef>(); JyoutaiDef WillPush; WillPush.BanArr = Enumerable.Range(1, pN).ToArray(); WillPush.Level = 0; WillPush.OniNum = 0; WillPush.OniInd = 0; WillPush.SumKyori = 0; WillPush.Log = new List<string>(); WillPush.Log.Add(CreateStrBanInfo(WillPush)); //1番を鬼に設定 WillPush.BanArr[0] = 0; WillPush.Level = 1; WillPush.OniNum = 1; WillPush.OniInd = 0; WillPush.SumKyori = pN; WillPush.Log.Add(CreateStrBanInfo(WillPush)); stk.Push(WillPush); int AnswerSumKyori = pLimitSumKyori; while (stk.Count > 0) { JyoutaiDef Popped = stk.Pop(); //クリア判定 if (IsClearBan(pN, Popped.BanArr)) { if (Popped.SumKyori < AnswerSumKyori) { AnswerSumKyori = Popped.SumKyori; Console.WriteLine("総走行距離={0}の解候補を発見", AnswerSumKyori); Popped.Log.ForEach(X => Console.WriteLine(X)); } continue; } //下限値枝切り if (Popped.SumKyori + pN + 1 >= AnswerSumKyori) continue; //鬼の走行距離でループ for (int I = 1; I <= pN - 1; I++) { int NewOniInd = Popped.OniInd + I; if (UB < NewOniInd) { NewOniInd -= (UB + 1); } WillPush.BanArr = (int[])Popped.BanArr.Clone(); WillPush.BanArr[NewOniInd] = Popped.OniNum; WillPush.Level = Popped.Level + 1; WillPush.OniNum = Popped.BanArr[NewOniInd]; WillPush.OniInd = NewOniInd; WillPush.SumKyori = Popped.SumKyori + pN + I; WillPush.Log = new List<string>(Popped.Log); WillPush.Log.Add(CreateStrBanInfo(WillPush)); stk.Push(WillPush); } } } //クリア状態の盤面かをチェック static bool IsClearBan(int pN, int[] pBanArr) { if (pBanArr.Contains(0)) return false; var NumList = new List<int>(); int StaInd = Array.FindIndex(pBanArr, X => X == pN); for (int I = StaInd; I <= UB; I++) { NumList.Add(pBanArr[I]); } for (int I = 0; I <= StaInd - 1; I++) { NumList.Add(pBanArr[I]); } return NumList.SequenceEqual(Enumerable.Range(1, pN).Reverse()); } //盤面の情報を返す static string CreateStrBanInfo(JyoutaiDef pJyoutai) { var sb = new System.Text.StringBuilder(); sb.AppendFormat("Level={0},SumKyori={1}", pJyoutai.Level, pJyoutai.SumKyori); sb.AppendLine(); for (int I = 0; I <= pJyoutai.BanArr.GetUpperBound(0); I++) { if (I == pJyoutai.OniInd) { sb.Append(pJyoutai.OniNum); } else sb.Append(" "); } sb.AppendLine(); for (int I = 0; I <= pJyoutai.BanArr.GetUpperBound(0); I++) { sb.Append(pJyoutai.BanArr[I]); if (I < pJyoutai.BanArr.GetUpperBound(0)) sb.Append(","); } sb.AppendLine(); return sb.ToString(); } }
省略 総走行距離=96の解候補を発見 Level=0,SumKyori=0 0 1,2,3,4,5,6,7,8 Level=1,SumKyori=8 1 0,2,3,4,5,6,7,8 Level=2,SumKyori=21 6 0,2,3,4,5,1,7,8 Level=3,SumKyori=33 2 0,6,3,4,5,1,7,8 Level=4,SumKyori=44 5 0,6,3,4,2,1,7,8 Level=5,SumKyori=58 3 0,6,5,4,2,1,7,8 Level=6,SumKyori=68 2 0,6,5,4,3,1,7,8 Level=7,SumKyori=77 1 0,6,5,4,3,2,7,8 Level=8,SumKyori=86 7 0,6,5,4,3,2,1,8 Level=9,SumKyori=96 0 7,6,5,4,3,2,1,8
深さ優先探索で解いてます。