トップページに戻る    次の増井さんの書籍の問題へ    前の増井さんの書籍の問題へ

Q13 覆面算を満たすのは何通り?


C#のソース

using System;
using System.Collections.Generic;

class Program
{
    struct JyouraiDef
    {
        internal int CurrP;
        internal Dictionary<char, int> NumDict;
    }

    static void Main()
    {
        //  READ
        // WRITE
        //  TALK
        //+-----
        // SKILL
        //として下位の桁から求める

        const string QuestionStr = "DEKL" + "ATLL" + "EIAI" + "ERTK" + "WS";
        int UB = QuestionStr.Length - 1;

        var stk = new Stack<JyouraiDef>();
        JyouraiDef WillPush;
        WillPush.CurrP = 0;
        WillPush.NumDict = new Dictionary<char, int>();
        stk.Push(WillPush);

        var AnswerList = new List<string>();
        while (stk.Count > 0) {
            JyouraiDef Popped = stk.Pop();
            //Console.WriteLine(Popped.CurrP);

            //クリア判定
            if (Popped.CurrP > UB) {
                AnswerList.Add(DeriveAnswerStr(Popped.NumDict));
                continue;
            }

            Action PushSyori = () =>
            {
                if (WillEdakiri(WillPush)) return;
                stk.Push(WillPush);
            };

            char CurrChar = QuestionStr[Popped.CurrP];
            WillPush.CurrP = Popped.CurrP + 1;
            if (Popped.NumDict.ContainsKey(CurrChar)) {
                WillPush.NumDict = Popped.NumDict;
                PushSyori();
            }
            else {
                for (int I = 0; I <= 9; I++) {
                    if (Popped.NumDict.ContainsValue(I)) continue;

                    //前ゼロは不可
                    if (CurrChar == 'R' && I == 0) continue;
                    if (CurrChar == 'W' && I == 0) continue;
                    if (CurrChar == 'T' && I == 0) continue;

                    //S != Wを満たせない場合はNG
                    if (CurrChar == 'W' && I == 9) continue;

                    WillPush.NumDict = new Dictionary<char, int>(Popped.NumDict);
                    WillPush.NumDict.Add(CurrChar, I);
                    PushSyori();
                }
            }
        }
        Console.WriteLine("解は{0}通り", AnswerList.Count);
        AnswerList.Sort();
        AnswerList.ForEach(X => Console.WriteLine(X));
    }

    static bool WillEdakiri(JyouraiDef pWillPush)
    {
        //1の位の和を返す
        Func<int> FuncSum1 = () =>
        {
            int wkSum = 0;
            wkSum += pWillPush.NumDict['D'];
            wkSum += pWillPush.NumDict['E'];
            wkSum += pWillPush.NumDict['K'];
            return wkSum;
        };
        //10の位の和を返す
        Func<int> FuncSum10 = () =>
        {
            int wkSum = 0;
            wkSum += pWillPush.NumDict['A'] * 10;
            wkSum += pWillPush.NumDict['T'] * 10;
            wkSum += pWillPush.NumDict['L'] * 10;
            return wkSum;
        };
        //100の位の和を返す
        Func<int> FuncSum100 = () =>
        {
            int wkSum = 0;
            wkSum += pWillPush.NumDict['E'] * 100;
            wkSum += pWillPush.NumDict['I'] * 100;
            wkSum += pWillPush.NumDict['A'] * 100;
            return wkSum;
        };
        //1000の位の和を返す
        Func<int> FuncSum1000 = () =>
        {
            int wkSum = 0;
            wkSum += pWillPush.NumDict['R'] * 1000;
            wkSum += pWillPush.NumDict['R'] * 1000;
            wkSum += pWillPush.NumDict['T'] * 1000;
            return wkSum;
        };
        //10000の位の和を返す
        Func<int> FuncSum10000 = () =>
        {
            int wkSum = 0;
            wkSum += pWillPush.NumDict['W'] * 10000;
            return wkSum;
        };

        //1桁目の和をチェック
        if (pWillPush.CurrP == 4) {
            int wkSum = FuncSum1();
            if (wkSum % 10 != pWillPush.NumDict['L'])
                return true;
        }
        //10桁目の和をチェック
        if (pWillPush.CurrP == 8) {
            int wkSum = FuncSum1() + FuncSum10();
            if (wkSum % 100 != pWillPush.NumDict['L'] * (10 + 1))
                return true;
        }
        //100桁目の和をチェック
        if (pWillPush.CurrP == 12) {
            int wkSum = FuncSum1() + FuncSum10() + FuncSum100();

            int wkResult = pWillPush.NumDict['L'] * (10 + 1);
            wkResult += pWillPush.NumDict['I'] * 100;
            if (wkSum % 1000 != wkResult)
                return true;
        }
        //1000桁目の和をチェック
        if (pWillPush.CurrP == 16) {
            int wkSum = FuncSum1() + FuncSum10() + FuncSum100() + FuncSum1000();

            int wkResult = pWillPush.NumDict['L'] * (10 + 1);
            wkResult += pWillPush.NumDict['I'] * 100;
            wkResult += pWillPush.NumDict['K'] * 1000;
            if (wkSum % 10000 != wkResult)
                return true;
        }
        //10000桁目の和をチェック
        if (pWillPush.CurrP == 18) {
            int wkSum = FuncSum1() + FuncSum10() + FuncSum100() + FuncSum1000() + FuncSum10000();

            int wkResult = pWillPush.NumDict['L'] * (10 + 1);
            wkResult += pWillPush.NumDict['I'] * 100;
            wkResult += pWillPush.NumDict['K'] * 1000;
            wkResult += pWillPush.NumDict['S'] * 10000;
            if (wkSum != wkResult)
                return true;
        }
        return false;
    }

    //解をString型に変換
    static string DeriveAnswerStr(Dictionary<char, int> pNumDict)
    {
        var sb = new System.Text.StringBuilder();
        Func<char, int> wkFunc = pChar => pNumDict[pChar];
        sb.AppendFormat("{0}{1}{2}{3}+",
            wkFunc('R'), wkFunc('E'), wkFunc('A'), wkFunc('D'));
        sb.AppendFormat("{0}{1}{2}{3}{4}+",
            wkFunc('W'), wkFunc('R'), wkFunc('I'), wkFunc('T'), wkFunc('E'));
        sb.AppendFormat("{0}{1}{2}{3}=",
            wkFunc('T'), wkFunc('A'), wkFunc('L'), wkFunc('K'));
        sb.AppendFormat("{0}{1}{2}{3}{4}",
            wkFunc('S'), wkFunc('K'), wkFunc('I'), wkFunc('L'), wkFunc('L'));
        return sb.ToString();
    }
}


実行結果



解説