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

コンピュータパズルへの招待 1問目 小町虫食算

問題

Fig.1の□に1〜9をひとつづつ配置して、
3つの3桁の数が全て素数となるようにしたら、和が3桁になった。
このような素数の組み合わせは何通りあるか?

Fig.1 小町虫食い算


ソース

<?php error_reporting(E_ALL);

const Jyougen = 999;
$SosuuArr = array();

Solve();

//エラトステネスの篩
function Eratosthenes()
{
GLOBAL $SosuuArr;
    for ($I = 2 ; $I <= Jyougen ; $I++){
        $SosuuArr[$I] = $I;
    }
    for ($I = 2; $I * $I <= Jyougen; $I++) {
        if ($I != 2 && $I % 2 == 0) continue;

        if ($SosuuArr[$I] != 0) {
            for ($J = $I * 2; $J <= Jyougen; $J += $I) {
                $SosuuArr[$J] = 0;
            }
        }
    }
    $SosuuArr = array_filter($SosuuArr,
                             function($pVal){
                                 return $pVal != 0
                                     && $pVal >= 100
                                     && IsValidVals(array($pVal));
                             });
    $SosuuArr = array_values($SosuuArr);
}

class JyoutaiDef
{
    public $CurrP;
    public $ValList;
}

function Solve()
{
GLOBAL $SosuuArr;
    Eratosthenes();

    $Stk = new SplStack();

    for ( $P = 0 ; $P <= count($SosuuArr) - 1 ; $P++){
        if ($SosuuArr[$P] * 3 > 999) break;
        $WillPush = new JyoutaiDef();
        $WillPush->CurrP = $P;
        $WillPush->ValList = array($SosuuArr[$P]);
        $Stk->push($WillPush);
    }

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

        if (count($Popped->ValList) == 3){
            $SumVal = array_sum($Popped->ValList);

            //和が3桁だったら
            if (100 <= $SumVal && $SumVal <= 999) {
                printf('解%dを発見' . PHP_EOL , ++$AnswerCnt);
                PrintAnswer($Popped->ValList);
            }
            continue;
        }

        for ($P = $Popped->CurrP + 1; $P <= count($SosuuArr) - 1 ; $P++) {
            $WillPush = new JyoutaiDef();
            $WillPush->CurrP = $P;
            $WillPush->ValList = array_merge($Popped->ValList , array($SosuuArr[$P]));
            if (IsValidVals($WillPush->ValList))
                $Stk->push($WillPush);
        }
    }
}

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

    foreach($pValList as $AnyInt){
        $CopiedVal = $AnyInt;
        do {
            $ModVal = $CopiedVal % 10;

            //0を含んだらNG
            if ($ModVal == 0) return false;

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

            $CopiedVal = ($CopiedVal - $CopiedVal % 10) / 10;
        } while ($CopiedVal > 0);
    }
    return true;
}

//解を表示
function PrintAnswer($pValList)
{
    for ( $I = 0; $I <= count($pValList) - 1; $I++) {
        echo $pValList[$I];
        if ($I < count($pValList) - 1) echo '+';
    }
    printf('=%d' , array_sum($pValList));
}


実行結果

解1を発見
149+263+587=999


解説

エラトステネスの篩で3桁の素数を列挙しておいてから、
深さ優先探索で検証してます。

C#で解いたもの