Fig.1のように、0〜9の数字が書かれたダイヤルが5つついた金庫がある。 この金庫、開け方がちょっと変わっている ([前提]、[操作手順]) 。 Fig.1の状態からたとえば03316→02316→12316→12315と動かすと、順に2、3、4、5で割り切れている。 しかし、次の6で割り切れる数を12315から作れないので、この場合はここでおしまい。 さて,金庫のセキュリティ上、できるだけ大きなNを設定したい。 ちゃんと金庫を開けることができる、最大のNはいくつだろうか。 [前提] 1) 左のダイヤルから万の位/千の位/百の位/十の位/一の位の数字を表しており、 この5桁の数を「D数」と呼ぶ。Fig.1のD数は「03316」 2) 除数nを考え、n=2 としてスタート [操作手順] 1) まず最初に、D数に偶数をセットする。当然、この数はn (=2)で割り切れる 2) 除数nに1を足す 3) どれか1つのダイヤルを選び、右か左に1だけ回す 4) 3) でセットされたD数が、nで割り切れれば5) へ。割り切れなければ金庫は開かずに終了 5) nがあらかじめ金庫に設定されている数Nと同じ場合、金庫が開く。n < Nなら2) へ Fig.1 割り算の得意な金庫 万 千 百 十 一 ↓ ↓ ↓ ↓ ↓ 901 234 234 012 567 8 2 1 5 1 5 9 3 4 8 7 3 0 6 0 6 8 4 3 9 654 987 987 765 210
using System; using System.Collections.Generic; class Program { const int UB = 5 - 1; static void Main() { for (int LoopN = 2; LoopN < int.MaxValue; LoopN++) { Console.WriteLine("N={0}で解を調査中", LoopN); if (ExecDFS(LoopN) == false) { Console.WriteLine("N={0}での解は、ありません。", LoopN); break; } } } struct JyoutaiDef { internal int NumVal; internal int CurrJyouSuu; internal List<int> Log; } //Nを引数として、深さ優先探索で解を探す static bool ExecDFS(int pN) { var stk = new Stack<JyoutaiDef>(); JyoutaiDef WillPush; for (int I = 0; I <= 99999; I += pN) { WillPush.NumVal = I; WillPush.CurrJyouSuu = pN; WillPush.Log = new List<int>() { I }; stk.Push(WillPush); } while (stk.Count > 0) { JyoutaiDef Popped = stk.Pop(); Popped.CurrJyouSuu--; //クリア判定 if (Popped.CurrJyouSuu == 1) { Console.WriteLine("解を発見"); Popped.Log.Reverse(); for (int I = 0; I <= Popped.Log.Count - 1; I++) { Console.Write(Popped.Log[I].ToString().PadLeft(5, '0')); if (I == Popped.Log.Count - 1 || I % 10 == 9) Console.WriteLine(); else Console.Write(","); } return true; } Action<int, bool> PushSyori = (pTargetInd, pIsPlus) => { List<int> NumList = DeriveNumList(Popped.NumVal); while (NumList.Count < 5) NumList.Add(0); int TargetIndNum = NumList[pTargetInd]; if (pIsPlus) { if (TargetIndNum == 9) TargetIndNum = 0; else TargetIndNum++; } else { if (TargetIndNum == 0) TargetIndNum = 9; else TargetIndNum--; } NumList[pTargetInd] = TargetIndNum; WillPush.NumVal = DeriveReversedNum(NumList); WillPush.CurrJyouSuu = Popped.CurrJyouSuu; if (WillPush.NumVal % WillPush.CurrJyouSuu > 0) return; WillPush.Log = new List<int>(Popped.Log) { WillPush.NumVal }; stk.Push(WillPush); }; //桁のループ for (int I = 0; I <= UB; I++) { PushSyori(I, false); PushSyori(I, true); } } return false; } //数値から数字のListを求めて返す static List<int> DeriveNumList(int pVal) { var WillReturn = new List<int>(); int CopiedVal = pVal; do { int ModVal = CopiedVal % 10; WillReturn.Add(ModVal); CopiedVal /= 10; } while (CopiedVal > 0); return WillReturn; } //数字を右から順に見た、数値を返す static int DeriveReversedNum(List<int> pNumList) { pNumList.Reverse(); int ReversedNum = 0; foreach (int EachNum in pNumList) { ReversedNum *= 10; ReversedNum += EachNum; } return ReversedNum; } }
省略 N=32で解を調査中 解を発見 14320,04320,05320,95320,85320,75320,76320,76329,76320,76329 76320,76310,76300,76200,77200,78200,78210,68210,68200,67200 68200,78200,79200,69200,69290,69390,69300,69310,69210,59210 59200 N=33で解を調査中 N=33での解は、ありません。
反復深化深さ優先探索チックに解いてます。