トップページに戻る    次のPHPのサンプルへ    前のPHPのサンプルへ

コンピュータパズルへの招待 2問目 時を掛けるパズル1

問題

Fig.Aの□を埋めてほしい。
それぞれ0〜9を1字ずつで御願いする。
分、秒には60以上の数が入らないことに注意。
ただし、*には0は入らない。

Fig.A 時を掛けるパズル1


ソース

<?php error_reporting(E_ALL);
$Stk = new SplStack();
for ( $I = 0; $I <= 9; $I++)
    $Stk->push(array('A' => $I));

while($Stk->isEmpty() == false){
    $Popped = $Stk->pop();

    $wkSet = array('A','B','C','D','E');
    $wkSet = array_diff($wkSet, array_keys($Popped));
    if(count($wkSet) == 0){
        GoalSyori($Popped);
        continue;
    }

    $WillSetKey = min($wkSet);
    for ( $I = 0; $I <= 9; $I++) {
        if ($WillSetKey == 'A' || $WillSetKey == 'E')
            if ($I == 0) continue;
        if ($WillSetKey == 'C' || $WillSetKey == 'E')
            if ($I >= 6) break;

        $Stk->push(array_merge($Popped,array($WillSetKey => $I)));
    }
}

//解に到達したら解を表示
function GoalSyori($pPopped)
{
    $wkSec = $pPopped['C'] * 10 + $pPopped['B'];
    $wkMinute = $pPopped['E'] * 10 + $pPopped['D'];

    //秒に換算してから掛け算
    $SumSec = ($wkMinute * 60 + $wkSec) * $pPopped['A'];

    $ResultArr = DeriveResultArr($SumSec);

    //10時間以上の場合はNG
    if ($ResultArr[0] >= 10) return;
    //1時間未満の場合はNG
    if ($ResultArr[0] < 1) return;

    //有効な数値リストかを判定
    if (IsValidNums(array_merge($pPopped,$ResultArr)) == false) return;

    printf("解を発見\n");
    printf("%d%d分%d%d秒 * %d = ",
        $pPopped['E'], $pPopped['D'], $pPopped['C'], $pPopped['B'], $pPopped['A']);
    printf("%d時間%d%d分%d%d秒",
        $ResultArr[0], $ResultArr[1], $ResultArr[2], $ResultArr[3], $ResultArr[4]);
}

//秒を引数として、時分秒に換算した配列を返す
function DeriveResultArr($pSumSec)
{
    $WillReturn = array();

    //時
    $wkHour = ($pSumSec - $pSumSec % 3600) / 3600;
    $WillReturn[0] = $wkHour;
    $pSumSec %= 3600;

    //分
    $wkMinute = ($pSumSec - $pSumSec % 60) / 60;
    $WillReturn[1] = ($wkMinute - $wkMinute % 10) / 10;
    $WillReturn[2] = $wkMinute % 10;
    $pSumSec %= 60;

    //秒
    $wkSecond = $pSumSec;
    $WillReturn[3] = ($wkSecond - $wkSecond % 10) / 10;
    $WillReturn[4] = $wkSecond % 10;

    return $WillReturn;
}

//有効な数値リストかを判定
function IsValidNums($pNumList)
{
    $IsAppearedArr = array();

    foreach($pNumList as $AnyInt){
        //同じ数字を2個以上含んだらNG
        if (array_key_exists($AnyInt,$IsAppearedArr)) return false;
        $IsAppearedArr[$AnyInt] = true;
    }
    return true;
}


実行結果

解を発見
50分42秒 * 9 = 7時間36分18秒


解説

 ED分CB秒
*     A
として、深さ優先探索で解を求めてます。

C#で解いたもの