using System;
using System.Collections.Generic;
class Program
{
const int UB = 12;
static void Main()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
//反復深化深さ優先探索で解く
for (int I = 5; I < int.MaxValue; I++) {
Console.WriteLine("レベル制限={0}で深さ優先探索中。経過時間={1}", I, sw.Elapsed);
if (ExecDFS(I)) break;
}
}
struct JyoutaiDef
{
internal int[] BanArr;
internal int Level;
internal List<string> Log;
}
//深さ優先探索を行う
static bool ExecDFS(int pLimitLevel)
{
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.BanArr = new int[UB + 1];
for (int I = 1; I <= 11; I++) {
WillPush.BanArr[I] = I;
}
WillPush.Level = 0;
WillPush.Log = new List<string>();
WillPush.Log.Add(BanToStr(WillPush.BanArr));
stk.Push(WillPush);
var MinTesuuDict = new Dictionary<ulong, int>();
MinTesuuDict.Add(GetHash(WillPush.BanArr), 0);
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
//クリア判定
if (IsClear(Popped.BanArr)) {
Console.WriteLine("解を発見");
for (int I = 0; I <= Popped.Log.Count - 1; I++) {
Console.WriteLine("■■■■■{0}手目■■■■■", I);
Console.WriteLine(Popped.Log[I]);
}
return true;
}
//下限値枝切り
if (Popped.Level + DeriveNeedMinTesuu(Popped.BanArr) > pLimitLevel)
continue;
//ボールを持ってない添字
int SpaceInd = Array.FindIndex(Popped.BanArr, 1, X => X == 0);
int[] FromIndArr = DeriveFromIndArr(SpaceInd);
foreach (int EachInt in FromIndArr) {
WillPush.BanArr = (int[])Popped.BanArr.Clone();
WillPush.BanArr[EachInt] = 0;
WillPush.BanArr[SpaceInd] = Popped.BanArr[EachInt];
WillPush.Level = Popped.Level + 1;
//メモ化探索
ulong wkHash = GetHash(WillPush.BanArr);
int MinTesuu;
if (MinTesuuDict.TryGetValue(wkHash, out MinTesuu)) {
if (MinTesuu <= WillPush.Level) continue;
}
MinTesuuDict[wkHash] = WillPush.Level;
WillPush.Log = new List<string>(Popped.Log);
WillPush.Log.Add(BanToStr(WillPush.BanArr));
stk.Push(WillPush);
}
}
return false;
}
//クリア判定
static bool IsClear(int[] pBanArr)
{
if (pBanArr[1] != 0) return false;
for (int I = 2; I <= 11; I++)
if (pBanArr[I] != I) return false;
if (pBanArr[12] != 1) return false;
return true;
}
//最小の残り手数を返す(下限値枝切り用)
static int DeriveNeedMinTesuu(int[] pBanArr)
{
int WillReturn = 0;
int wkInd = 0;
Action<int, int> wkAct = (pInd, pTesuu) =>
{
if (wkInd == pInd) WillReturn += pTesuu;
};
//1のボールを12まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 1);
wkAct(1, 5); wkAct(2, 5); wkAct(3, 3); wkAct(4, 3); wkAct(5, 1); wkAct(6, 1);
wkAct(7, 6); wkAct(8, 4); wkAct(9, 4); wkAct(10, 2); wkAct(11, 2); wkAct(12, 0);
//2のボールを2まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 2);
wkAct(1, 2); wkAct(2, 0); wkAct(3, 2); wkAct(4, 2); wkAct(5, 4); wkAct(6, 4);
wkAct(7, 1); wkAct(8, 1); wkAct(9, 1); wkAct(10, 3); wkAct(11, 3); wkAct(12, 5);
//3のボールを3まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 3);
wkAct(1, 2); wkAct(2, 2); wkAct(3, 0); wkAct(4, 2); wkAct(5, 2); wkAct(6, 4);
wkAct(7, 3); wkAct(8, 1); wkAct(9, 1); wkAct(10, 1); wkAct(11, 3); wkAct(12, 3);
//4のボールを4まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 4);
wkAct(1, 4); wkAct(2, 2); wkAct(3, 2); wkAct(4, 0); wkAct(5, 2); wkAct(6, 2);
wkAct(7, 3); wkAct(8, 3); wkAct(9, 1); wkAct(10, 1); wkAct(11, 1); wkAct(12, 3);
//5のボールを5まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 5);
wkAct(1, 4); wkAct(2, 4); wkAct(3, 2); wkAct(4, 2); wkAct(5, 0); wkAct(6, 2);
wkAct(7, 5); wkAct(8, 3); wkAct(9, 3); wkAct(10, 1); wkAct(11, 1); wkAct(12, 1);
//6のボールを6まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 6);
wkAct(1, 6); wkAct(2, 4); wkAct(3, 4); wkAct(4, 2); wkAct(5, 2); wkAct(6, 0);
wkAct(7, 5); wkAct(8, 5); wkAct(9, 3); wkAct(10, 3); wkAct(11, 1); wkAct(12, 1);
//7のボールを7まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 7);
wkAct(1, 1); wkAct(2, 1); wkAct(3, 3); wkAct(4, 3); wkAct(5, 5); wkAct(6, 5);
wkAct(7, 0); wkAct(8, 2); wkAct(9, 2); wkAct(10, 4); wkAct(11, 4); wkAct(12, 6);
//8のボールを8まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 8);
wkAct(1, 1); wkAct(2, 1); wkAct(3, 1); wkAct(4, 3); wkAct(5, 3); wkAct(6, 5);
wkAct(7, 2); wkAct(8, 0); wkAct(9, 2); wkAct(10, 2); wkAct(11, 4); wkAct(12, 4);
//9のボールを9まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 9);
wkAct(1, 3); wkAct(2, 1); wkAct(3, 1); wkAct(4, 1); wkAct(5, 3); wkAct(6, 3);
wkAct(7, 2); wkAct(8, 2); wkAct(9, 0); wkAct(10, 2); wkAct(11, 2); wkAct(12, 4);
//10のボールを10まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 10);
wkAct(1, 3); wkAct(2, 3); wkAct(3, 1); wkAct(4, 1); wkAct(5, 1); wkAct(6, 3);
wkAct(7, 4); wkAct(8, 2); wkAct(9, 2); wkAct(10, 0); wkAct(11, 2); wkAct(12, 2);
//11のボールを11まで移動させる手数
wkInd = Array.FindIndex(pBanArr, 1, X => X == 11);
wkAct(1, 5); wkAct(2, 3); wkAct(3, 3); wkAct(4, 1); wkAct(5, 1); wkAct(6, 1);
wkAct(7, 4); wkAct(8, 4); wkAct(9, 2); wkAct(10, 2); wkAct(11, 0); wkAct(12, 2);
return WillReturn;
}
//ボールを投げれる添字の配列を返す
static int[] DeriveFromIndArr(int pSpaceInd)
{
if (pSpaceInd == 1) return new int[] { 7, 8 };
if (pSpaceInd == 2) return new int[] { 7, 8, 9 };
if (pSpaceInd == 3) return new int[] { 8, 9, 10 };
if (pSpaceInd == 4) return new int[] { 9, 10, 11 };
if (pSpaceInd == 5) return new int[] { 10, 11, 12 };
if (pSpaceInd == 6) return new int[] { 11, 12 };
if (pSpaceInd == 7) return new int[] { 1, 2 };
if (pSpaceInd == 8) return new int[] { 1, 2, 3 };
if (pSpaceInd == 9) return new int[] { 2, 3, 4 };
if (pSpaceInd == 10) return new int[] { 3, 4, 5 };
if (pSpaceInd == 11) return new int[] { 4, 5, 6 };
if (pSpaceInd == 12) return new int[] { 5, 6 };
return null;
}
//盤面をハッシュ値に変換
static ulong GetHash(int[] pBanArr)
{
var sb = new System.Text.StringBuilder();
for (int I = 1; I <= UB; I++) {
sb.Append(pBanArr[I]);
}
return Convert.ToUInt64(sb.ToString());
}
//盤面をString型で表現
static string BanToStr(int[] pBanArr)
{
var sb = new System.Text.StringBuilder();
for (int I = 1; I <= UB; I++) {
sb.AppendFormat("{0,2},", pBanArr[I]);
if (I == 6) sb.AppendLine();
}
sb.AppendLine();
return sb.ToString();
}
}
省略
レベル制限=35で深さ優先探索中。経過時間=00:00:03.5120958
レベル制限=36で深さ優先探索中。経過時間=00:00:05.1939481
レベル制限=37で深さ優先探索中。経過時間=00:00:06.8724265
解を発見
■■■■■0手目■■■■■
1, 2, 3, 4, 5, 6,
7, 8, 9,10,11, 0,
■■■■■1手目■■■■■
1, 2, 3, 4, 5, 0,
7, 8, 9,10,11, 6,
■■■■■2手目■■■■■
1, 2, 3, 4, 5,11,
7, 8, 9,10, 0, 6,
■■■■■3手目■■■■■
1, 2, 3, 4, 0,11,
7, 8, 9,10, 5, 6,
■■■■■4手目■■■■■
1, 2, 3, 4,10,11,
7, 8, 9, 0, 5, 6,
■■■■■5手目■■■■■
1, 2, 3, 0,10,11,
7, 8, 9, 4, 5, 6,
■■■■■6手目■■■■■
1, 2, 3, 9,10,11,
7, 8, 0, 4, 5, 6,
■■■■■7手目■■■■■
1, 2, 0, 9,10,11,
7, 8, 3, 4, 5, 6,
■■■■■8手目■■■■■
1, 2, 8, 9,10,11,
7, 0, 3, 4, 5, 6,
■■■■■9手目■■■■■
0, 2, 8, 9,10,11,
7, 1, 3, 4, 5, 6,
■■■■■10手目■■■■■
7, 2, 8, 9,10,11,
0, 1, 3, 4, 5, 6,
■■■■■11手目■■■■■
7, 0, 8, 9,10,11,
2, 1, 3, 4, 5, 6,
■■■■■12手目■■■■■
7, 3, 8, 9,10,11,
2, 1, 0, 4, 5, 6,
■■■■■13手目■■■■■
7, 3, 0, 9,10,11,
2, 1, 8, 4, 5, 6,
■■■■■14手目■■■■■
7, 3, 1, 9,10,11,
2, 0, 8, 4, 5, 6,
■■■■■15手目■■■■■
7, 0, 1, 9,10,11,
2, 3, 8, 4, 5, 6,
■■■■■16手目■■■■■
7, 8, 1, 9,10,11,
2, 3, 0, 4, 5, 6,
■■■■■17手目■■■■■
7, 8, 1, 0,10,11,
2, 3, 9, 4, 5, 6,
■■■■■18手目■■■■■
7, 8, 1, 4,10,11,
2, 3, 9, 0, 5, 6,
■■■■■19手目■■■■■
7, 8, 0, 4,10,11,
2, 3, 9, 1, 5, 6,
■■■■■20手目■■■■■
7, 8, 9, 4,10,11,
2, 3, 0, 1, 5, 6,
■■■■■21手目■■■■■
7, 8, 9, 0,10,11,
2, 3, 4, 1, 5, 6,
■■■■■22手目■■■■■
7, 8, 9, 5,10,11,
2, 3, 4, 1, 0, 6,
■■■■■23手目■■■■■
7, 8, 9, 5, 0,11,
2, 3, 4, 1,10, 6,
■■■■■24手目■■■■■
7, 8, 9, 5, 1,11,
2, 3, 4, 0,10, 6,
■■■■■25手目■■■■■
7, 8, 9, 0, 1,11,
2, 3, 4, 5,10, 6,
■■■■■26手目■■■■■
7, 8, 9,10, 1,11,
2, 3, 4, 5, 0, 6,
■■■■■27手目■■■■■
7, 8, 9,10, 1, 0,
2, 3, 4, 5,11, 6,
■■■■■28手目■■■■■
7, 8, 9,10, 1, 6,
2, 3, 4, 5,11, 0,
■■■■■29手目■■■■■
7, 8, 9,10, 0, 6,
2, 3, 4, 5,11, 1,
■■■■■30手目■■■■■
7, 8, 9,10, 5, 6,
2, 3, 4, 0,11, 1,
■■■■■31手目■■■■■
7, 8, 9, 0, 5, 6,
2, 3, 4,10,11, 1,
■■■■■32手目■■■■■
7, 8, 9, 4, 5, 6,
2, 3, 0,10,11, 1,
■■■■■33手目■■■■■
7, 8, 0, 4, 5, 6,
2, 3, 9,10,11, 1,
■■■■■34手目■■■■■
7, 8, 3, 4, 5, 6,
2, 0, 9,10,11, 1,
■■■■■35手目■■■■■
7, 0, 3, 4, 5, 6,
2, 8, 9,10,11, 1,
■■■■■36手目■■■■■
7, 2, 3, 4, 5, 6,
0, 8, 9,10,11, 1,
■■■■■37手目■■■■■
0, 2, 3, 4, 5, 6,
7, 8, 9,10,11, 1,