5

こんにちは私はCryptarithmsと呼ばれる有名な種類の単語と数字ベースのパズルのサブセットであるこのパズルに出くわしました。あなたが次のような表現をしているとしましょう

SEND + MORE = MONEY

ここで興味深いのは、各アルファベットが0から9までの一意の数字を表していることです。一般化されたソルバーを書きたかったのですが、結局はそのためのブルートフォースソリューションを書きました。どうすればそれを解決できますか?

述語論理や集合論で解けると思います。そして、私は特にC#またはPythonベースのソリューションを見つけることに興味があります。誰。?

4

5 に答える 5

7

PyCon 2009 で、Raymond Hettinger は Python での AI プログラミングについて話し、Cryptarithms について取り上げました。

トーク全体のビデオはここで見ることができ、Python 2.6 ソリューションのクックブックはこのリンクで見つけることができます。

于 2009-04-15T10:48:01.217 に答える
2

これは非常に小さな問題であるため、力ずくの解決策は悪い方法ではありません。各文字が一意の数字を表す必要があると仮定すると(つまり、解S = 9、M = 1、* = 0)、試行する組み合わせの数はnであることがわかります。、ここで、nは覆面算内の一意の文字の数です。評価する組み合わせの理論上の最大数は10です!= 3 628 800、これはコンピューターとしては非常に少ない数です。

複数の文字が同じ数を表すことを許可する場合、試行する組み合わせの数は10 ^ nで制限されます。ここでも、nは一意の文字の数です。大文字の英字のみを想定すると、理論上の最大組み合わせ数は10 ^ 26であるため、その理論上の最悪の場合には、いくつかのヒューリスティックが必要になる可能性があります。ただし、ほとんどの実用的な暗号化では、固有の文字が26文字よりはるかに少ないため、通常の場合は、おそらく10未満のnで囲まれます。これも、コンピューターにとってはかなり合理的です。

于 2009-04-15T10:37:17.140 に答える
1

これは、すべての可能性を再帰的に循環するだけでなく、特定の問題の構造に注意して問題を短縮する効率的なブルートフォース手法です。

各メソッドの最初のいくつかの引数は、各ブランチの試行値を表します。引数v1、v2などはまだ割り当てられていない値であり、任意の順序で渡すことができます。この方法は、ブルートフォースによる10!/ 2の可能なソリューションではなく、最大8x7x5の可能なトライアルソリューションを備えているため、効率的です。

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

namespace ConsoleApplication1
{
    class Program
    {
        static void MESDYNR(int m, int s, int e, int d, int y, int n, int r, int v1, int v2, int v3)
        {
            // Solve for O in hundreds position
            // "SEND" + "M?RE" = "M?NEY"
            int carry = (10 * n + d + 10 * r + e) / 100;
            int o = (10 + n - (e + carry))%10;

            if ((v1 == o) || (v2 == o) || (v3 == o)) 
            {
                // check O is valid in thousands position
                if (o == ((10 + (100 * e + 10 * n + d + 100 * o + 10 * r + e) / 1000 + m + s) % 10))
                {
                    // "SEND" + "MORE" = "MONEY"
                    int send = 1000 * s + 100 * e + 10 * n + d;
                    int more = 1000 * m + 100 * o + 10 * r + e;
                    int money = 10000 * m + 1000 * o + 100 * n + 10 * e + y;

                    // Chck this solution
                    if ((send + more) == money)
                    {
                        Console.WriteLine(send + " + " + more + " = " + money);
                    }
                }
            }
        }

        static void MSEDYN(int m, int s, int e, int d, int y, int n, int v1, int v2, int v3, int v4)
        {
            // Solve for R
            // "SEND" + "M*?E" = "M*NEY"
            int carry = (d + e) / 10;
            int r = (10 + e - (n + carry)) % 10;

            if (v1 == r) MESDYNR(m, s, e, d, y, n, r, v2, v3, v4);
            else if (v2 == r) MESDYNR(m, s, e, d, y, n, r, v1, v3, v4);
            else if (v3 == r) MESDYNR(m, s, e, d, y, n, r, v1, v2, v4);
            else if (v4 == r) MESDYNR(m, s, e, d, y, n, r, v1, v2, v3);
        }

        static void MSEDY(int m, int s, int e, int d, int y, int v1, int v2, int v3, int v4, int v5)
        {
            // Pick any value for N
            MSEDYN(m, s, e, d, y, v1, v2, v3, v4, v5);
            MSEDYN(m, s, e, d, y, v2, v1, v3, v4, v5);
            MSEDYN(m, s, e, d, y, v3, v1, v2, v4, v5);
            MSEDYN(m, s, e, d, y, v4, v1, v2, v3, v5);
            MSEDYN(m, s, e, d, y, v5, v1, v2, v3, v4);
        }

        static void MSED(int m, int s, int e, int d, int v1, int v2, int v3, int v4, int v5, int v6)
        {
            // Solve for Y
            // "SE*D" + "M**E" = "M**E?"
            int y = (e + d) % 10;

            if (v1 == y) MSEDY(m, s, e, d, y, v2, v3, v4, v5, v6);
            else if (v2 == y) MSEDY(m, s, e, d, y, v1, v3, v4, v5, v6);
            else if (v3 == y) MSEDY(m, s, e, d, y, v1, v2, v4, v5, v6);
            else if (v4 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v5, v6);
            else if (v5 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v4, v6);
            else if (v6 == y) MSEDY(m, s, e, d, y, v1, v2, v3, v4, v5);
        }

        static void MSE(int m, int s, int e, int v1, int v2, int v3, int v4, int v5, int v6, int v7)
        {
            // "SE**" + "M**E" = "M**E*"
            // Pick any value for D
            MSED(m, s, e, v1, v2, v3, v4, v5, v6, v7);
            MSED(m, s, e, v2, v1, v3, v4, v5, v6, v7);
            MSED(m, s, e, v3, v1, v2, v4, v5, v6, v7);
            MSED(m, s, e, v4, v1, v2, v3, v5, v6, v7);
            MSED(m, s, e, v5, v1, v2, v3, v4, v6, v7);
            MSED(m, s, e, v6, v1, v2, v3, v4, v5, v7);
            MSED(m, s, e, v7, v1, v2, v3, v4, v5, v6);
        }


        static void MS(int m, int s, int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8)
        {
            // "S***" + "M***" = "M****"
            // Pick any value for E
            MSE(m, s, v1, v2, v3, v4, v5, v6, v7, v8);
            MSE(m, s, v2, v1, v3, v4, v5, v6, v7, v8);
            MSE(m, s, v3, v1, v2, v4, v5, v6, v7, v8);
            MSE(m, s, v4, v1, v2, v3, v5, v6, v7, v8);
            MSE(m, s, v5, v1, v2, v3, v4, v6, v7, v8);
            MSE(m, s, v6, v1, v2, v3, v4, v5, v7, v8);
            MSE(m, s, v7, v1, v2, v3, v4, v5, v6, v8);
            MSE(m, s, v8, v1, v2, v3, v4, v5, v6, v7);
         }

        static void Main(string[] args)
        {
            // M must be 1
            // S must be 8 or 9
            DateTime Start = DateTime.Now;
            MS(1, 8, 2, 3, 4, 5, 6, 7, 9, 0);
            MS(1, 9, 2, 3, 4, 5, 6, 7, 8, 0);
            Console.WriteLine((DateTime.Now-Start).Milliseconds);
            return;
        }
    }
}
于 2012-03-10T15:40:27.027 に答える
1

さて、関数のリストとしてそれを書いてみてください:

 SEND
 MORE
----+
MONEY

私の低学年の数学を覚えているなら、これは次のようになります。

Y = (D+E) mod 10
E = ((N+R) + (D+E)/10) mod 10
...
于 2009-04-15T10:54:12.623 に答える