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での解は、ありません。
反復深化深さ優先探索チックに解いてます。