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

Q42 1つの数字で作る1234


C#のソース

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        for (int LoopNumCnt = 1; LoopNumCnt < int.MaxValue; LoopNumCnt++) {
            var AnswerList = new List<string>();
            for (int LoopNum = 1; LoopNum <= 9; LoopNum++) {
                AnswerList.AddRange(DeriveAnswerList(LoopNum, LoopNumCnt));
            }
            if (AnswerList.Count > 0) {
                Console.WriteLine("数字の個数={0}の解を発見", LoopNumCnt);
                AnswerList.ForEach(X => Console.WriteLine("{0} = 1234", X));
                break;
            }
        }
    }

    //数字と個数と引数として、1234になる数式のListを返す
    static List<string> DeriveAnswerList(int pNum, int pNumCnt)
    {
        var WillReturn = new List<string>();

        var SuusikiList = new List<string>();
        var stk = new Stack<string>();
        var InitStr = new System.Text.StringBuilder();
        for (int I = 1; I <= pNumCnt; I++) {
            InitStr.Append(pNum);
            if (I < pNumCnt) InitStr.Append('□');
        }
        stk.Push(InitStr.ToString());

        while (stk.Count > 0) {
            string Popped = stk.Pop();

            int Ind = Popped.IndexOf('□');
            if (Ind == -1) {
                SuusikiList.Add(Popped);
                continue;
            }

            string wkStr = Popped.Remove(Ind, 1);
            stk.Push(wkStr);
            stk.Push(wkStr.Insert(Ind, "+"));
            stk.Push(wkStr.Insert(Ind, "-"));
            stk.Push(wkStr.Insert(Ind, "*"));
            stk.Push(wkStr.Insert(Ind, "/"));
        }
        foreach (string EachStr in SuusikiList) {
            if (CalcFromRPN(ToRPN(EachStr)) == 1234) {
                WillReturn.Add(EachStr);
            }
        }
        return WillReturn;
    }

    //数式を逆ポーランド記法にした配列を返す
    static string[] ToRPN(string pTargetStr)
    {
        var WillReturn = new List<string>();

        var stk = new Stack<string>();
        string[] WkStrArr = MakeNumAndExpArr(pTargetStr);

        foreach (string EachStr in WkStrArr) {
            if (EachStr == "+" || EachStr == "-" || EachStr == "*" || EachStr == "/") {
                int Priority = DerivePriority(EachStr);

                while (stk.Count > 0 && Priority <= DerivePriority(stk.Peek())) {
                    WillReturn.Add(stk.Pop());
                }
                stk.Push(EachStr);
            }
            else WillReturn.Add(EachStr);
        }
        while (stk.Count > 0) WillReturn.Add(stk.Pop());
        return WillReturn.ToArray();
    }

    //数式から数値と演算子の配列を作成
    static string[] MakeNumAndExpArr(string pTargetStr)
    {
        var WillReturn = new List<string>();
        var sb = new System.Text.StringBuilder();

        foreach (Char EachChar in pTargetStr) {
            if (EachChar == '+' || EachChar == '-' || EachChar == '*' || EachChar == '/') {
                WillReturn.Add(sb.ToString()); sb.Length = 0;
                WillReturn.Add(EachChar.ToString());
            }
            else sb.Append(EachChar);
        }
        WillReturn.Add(sb.ToString());
        return WillReturn.ToArray();
    }

    //演算子のプライオリティを返す
    static int DerivePriority(string pOperator)
    {
        if (pOperator == "+") return 1;
        if (pOperator == "-") return 1;
        if (pOperator == "*") return 2;
        if (pOperator == "/") return 2;
        return 0;
    }

    //逆ポーランド記法のListジェネリックを計算した結果を返す
    static long CalcFromRPN(string[] pRPNArr)
    {
        var stk = new Stack<long>();

        foreach (string EachStr in pRPNArr) {
            if (EachStr == "+" || EachStr == "-" || EachStr == "*" || EachStr == "/") {
                long exp2 = stk.Pop();
                long exp1 = stk.Pop();
                if (EachStr == "+") stk.Push(exp1 + exp2);
                if (EachStr == "-") stk.Push(exp1 - exp2);
                if (EachStr == "*") stk.Push(exp1 * exp2);
                if (EachStr == "/") stk.Push(exp1 / exp2);
                continue;
            }
            stk.Push(long.Parse(EachStr));
        }
        return stk.Pop();
    }
}


実行結果

数字の個数=7の解を発見
99999/9/9 = 1234


解説

数式を逆ポーランド記法に変換してから、計算してます。