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

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

問題

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

Fig.1 小町虫食い算


ソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    const int Jyougen = 999;
    static int[] SosuuArr = new int[Jyougen + 1];

    //エラトステネスの篩
    static void Eratosthenes()
    {
        for (int I = 2; I <= SosuuArr.GetUpperBound(0); I++) {
            SosuuArr[I] = I;
        }
        for (int I = 2; I * I <= SosuuArr.GetUpperBound(0); I++) {
            if (I != 2 && I % 2 == 0) continue;

            if (SosuuArr[I] != 0) {
                for (int J = I * 2; J <= SosuuArr.GetUpperBound(0); J += I) {
                    SosuuArr[J] = 0;
                }
            }
        }

        SosuuArr = SosuuArr.Where(X => X != 0).ToArray();
        SosuuArr = SosuuArr.Where(X => 100 <= X).ToArray();
        SosuuArr = SosuuArr.Where(X => IsValidVals(new List<int>() { X })).ToArray();
    }

    struct JyoutaiDef
    {
        internal int CurrP;
        internal List<int> ValList;
    }

    static void Main()
    {
        Eratosthenes();

        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        for (int P = 0; P <= SosuuArr.GetUpperBound(0); P++) {
            if (SosuuArr[P] * 3 > 999) break;
            WillPush.CurrP = P;
            WillPush.ValList = new List<int>() { SosuuArr[P] };
            stk.Push(WillPush);
        }

        int AnswerCnt = 0;
        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();

            if (Popped.ValList.Count == 3) {
                int SumVal = Popped.ValList.Sum();

                //和が3桁だったら
                if (100 <= SumVal && SumVal <= 999) {
                    Console.WriteLine("解{0}を発見", ++AnswerCnt);
                    PrintAnswer(Popped.ValList);
                }
                continue;
            }

            for (int P = Popped.CurrP + 1; P <= SosuuArr.GetUpperBound(0); P++) {
                WillPush.CurrP = P;
                WillPush.ValList = new List<int>(Popped.ValList) { SosuuArr[P] };
                if (IsValidVals(WillPush.ValList))
                    stk.Push(WillPush);
            }
        }
    }

    //有効な数値リストかを判定
    static bool IsValidVals(List<int> pValList)
    {
        bool[] IsAppearedArr = new bool[10];

        foreach (int AnyInt in pValList) {
            int CopiedVal = AnyInt;
            do {
                int ModVal = CopiedVal % 10;

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

                //同じ数字を2個以上含んだらNG
                if (IsAppearedArr[ModVal]) return false;
                IsAppearedArr[ModVal] = true;
            } while ((CopiedVal /= 10) > 0);
        }
        return true;
    }

    //解を表示
    static void PrintAnswer(List<int> pValList)
    {
        for (int I = 0; I <= pValList.Count - 1; I++) {
            Console.Write("{0}", pValList[I]);
            if (I < pValList.Count - 1) Console.Write('+');
        }
        Console.WriteLine("={0}", pValList.Sum());
    }
}


実行結果

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


解説

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