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

Cマガ電脳クラブ(第086回) 掛けても足しても

問題

2*42*8    = 24*28   (1)
73*9*42   =  7*3942 (2)
1803*60*6 =180*3606 (3)
この式をよく見ると、おもしろいことに、
どれも「数字の並び」が右辺と左辺で同じになっていることがわかる。

このようなものは、ほかにもまだたくさんある。ここで、'*'を'+'に置き換えてみると、
(1)だけがまだ成立している。
2+42+8=24+28        (1')

このように'*'と'+'の置き換えに対応するものは、両辺がそれぞれ4個の数字で構成される場合、
ほかにもう1解存在する(3*74*8=37*48)。
では、(2)や(3)のように両辺それぞれ5個以上の数字で構成されるものではどうだろうか。
5個から初めて、最初に成立する数字の個数と、その個数で作れる解をすべてあげていただきたい。

なお、例のように左辺は3数の掛け算(足し算)、右辺は2数の掛け算(足し算)という形に限定する。
また、0は式のなかの各数の左端には置けないものとする。


ソース

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

class Program
{
    const int Jyougen = 9999999;

    static void Main()
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();

        for (int I = 100; I <= Jyougen; I++) {
            List<int[]> Num2ArrList = DeriveNum2ArrList(I.ToString());
            var CalcedArr = Num2ArrList.Select(
                X => new { SumVal = X.Sum(), ProdVal = DeriveProd(X) }).ToArray();

            List<int[]> Num3ArrList = DeriveNum3ArrList(I.ToString());

            foreach (int[] EachNum3Arr in Num3ArrList) {
                int wkSumVal = EachNum3Arr.Sum();
                int wkProdVal = DeriveProd(EachNum3Arr);

                int wkInd = Array.FindIndex(
                    CalcedArr, X => X.SumVal == wkSumVal && X.ProdVal == wkProdVal);
                if (wkInd >= 0) {
                    Console.WriteLine("{0}で解を発見。経過時間={1}", I, sw.Elapsed);

                    Action<int[]> wkAct = pArr =>
                    {
                        for (int J = 0; J <= pArr.GetUpperBound(0); J++) {
                            Console.Write(pArr[J]);
                            if (J < pArr.GetUpperBound(0))
                                Console.Write("+(*)");
                        }
                    };
                    wkAct(EachNum3Arr); Console.Write(" = ");
                    wkAct(Num2ArrList[wkInd]); Console.WriteLine();
                }
            }
        }
        Console.WriteLine("終了しました。経過時間={0}", sw.Elapsed);
    }

    //数値を2つの数値に分割する
    static List<int[]> DeriveNum2ArrList(string pTargetNumStr)
    {
        var WillReturn = new List<int[]>();
        int UB = pTargetNumStr.Length - 1;
        for (int I = 1; I <= UB; I++) {
            string wkNumStr1 = pTargetNumStr.Substring(0, I);
            string wkNumStr2 = pTargetNumStr.Substring(I);

            //左端のゼロは不許可
            if (wkNumStr1.StartsWith("0")) continue;
            if (wkNumStr2.StartsWith("0")) continue;

            WillReturn.Add(new int[] { int.Parse(wkNumStr1), int.Parse(wkNumStr2) });
        }
        return WillReturn;
    }

    //数値を3つの数値に分割する
    static List<int[]> DeriveNum3ArrList(string pTargetNumStr)
    {
        var WillReturn = new List<int[]>();
        int UB = pTargetNumStr.Length - 1;
        for (int I = 1; I <= UB - 2; I++) {
            for (int J = I + 1; J <= UB - 1; J++) {
                string wkNumStr1 = pTargetNumStr.Substring(0, I);
                string wkNumStr2 = pTargetNumStr.Substring(I, J - I + 1);
                string wkNumStr3 = pTargetNumStr.Substring(J + 1);

                //左端のゼロは不許可
                if (wkNumStr1.StartsWith("0")) continue;
                if (wkNumStr2.StartsWith("0")) continue;
                if (wkNumStr3.StartsWith("0")) continue;

                WillReturn.Add(
                    new int[] { int.Parse(wkNumStr1), int.Parse(wkNumStr2), int.Parse(wkNumStr3) });
            }
        }
        return WillReturn;
    }

    //配列の総積を求める
    static int DeriveProd(int[] pTargetArr)
    {
        int WillReturn = 1;
        Array.ForEach(pTargetArr, X => WillReturn *= X);
        return WillReturn;
    }
}


実行結果

2428で解を発見。経過時間=00:00:00.0460849
2+(*)42+(*)8 = 24+(*)28
3748で解を発見。経過時間=00:00:00.0714381
3+(*)74+(*)8 = 37+(*)48
8322480で解を発見。経過時間=00:06:33.7583058
8+(*)3224+(*)80 = 832+(*)2480
終了しました。経過時間=00:07:58.7727091


解説

数値をループさせつつ、数値の分割の仕方を列挙して検証してます。