6

暗号演算パズルが与えられたとします。

送信 + もっと = お金

目標は、数字 (0 ~ 9) を文字に置き換えて、足し算がうまくいくようにすることです。

問題に数学的にアプローチする方法は理解していますが、リレーショナル データベースでこれを解決する方法がわかりません。

この問題にアプローチするには、スキーマをどのように設計すればよいでしょうか?

この問題を解決しようとする SQL クエリはどのように見えるでしょうか?

編集: いくつかの制約があります:

  1. 全体を通して、特定の文字には同じ番号を使用する必要があります。たとえば、文字 E の "5" を推測した場合、E は出現するすべての場所で値 "5" を取得する必要があります。
  2. たとえば、「4」を E と M の両方に割り当てることはできません。
  3. 数字 (単語) の先頭に 0 を付けないでください
4

2 に答える 2

7

これは、ユーザーが提起する他の問題に答えます。

SEND + MORE = MONEYここで、各文字には一意の数字があり、ゼロで始まる単語はありません。

select
    top 1
    S.num as S,
    E.num as E,
    N.num as N,
    D.num as D,
    M.num as M,
    O.num as O,
    R.num as R,
    Y.num as Y,
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num) as [SEND],
    (M.num * 1000 + O.num * 100 + R.num * 10 + E.num) as MORE,
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num) + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num) as SEND_plus_MORE,
    (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num) as [MONEY]

from
    Digits as S
    join digits as E on E.num <> S.num
    join digits as N on N.num <> S.num and N.num <> E.num
    join digits as D on D.num <> S.num and D.num <> E.num and D.num <> N.num
    join digits as M on M.num <> S.num and M.num <> E.num and M.num <> N.num and M.num <> D.num
    join digits as O on O.num <> S.num and O.num <> E.num and O.num <> N.num and O.num <> D.num and O.num <> M.num
    join digits as R on R.num <> S.num and R.num <> E.num and R.num <> N.num and R.num <> D.num and R.num <> M.num and R.num <> O.num
    join digits as Y on Y.num <> S.num and Y.num <> E.num and Y.num <> N.num and Y.num <> D.num and Y.num <> M.num and Y.num <> O.num and Y.num <> R.num

where
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num)
    + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num)
    = (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num)     
    and S.num <> 0 and M.num <> 0

WHERE句で一意の数字を強制することを考えましたが、WHERE句がチェックされる前に処理する順列が多すぎると思います。

最大10桁しか扱っていないので、速度の問題ではなく、長いON句を作成するのが最善だと思います。

これは、クレイジーなON句のないFROM+WHERE句です。これにより、サーバーの実行速度が大幅に低下します。

from
    Digits as S
    cross join digits as E
    cross join digits as N
    cross join digits as D
    cross join digits as M
    cross join digits as O
    cross join digits as R
    cross join digits as Y

where
    (S.num * 1000 + E.num * 100 + N.num * 10 + D.num)
    + (M.num * 1000 + O.num * 100 + R.num * 10 + E.num)
    = (M.num * 10000 + O.num * 1000 + N.num * 100 + E.num * 10 + Y.num)     
    and S.num <> 0 and M.num <> 0

        and (select max(B.Count) from   
                (select COUNT(*) as Count from 
                    (select S.num, 's' as letter   -- the letters are included to make sure the unions do not merge equivalent rows
                    UNION select E.num, 'e'
                    UNION select N.num, 'n'
                    UNION select D.num, 'd'
                    UNION select M.num, 'm'
                    UNION select O.num, 'o'
                    UNION select R.num, 'r'
                    UNION select Y.num, 'y') as A
                    group by A.num
                ) as B
             ) = 1
于 2013-02-27T05:30:44.370 に答える
5

著者は、2 つの異なる問題を提起します。

これは、各文字が必ずしも一意の数字を持っているとは限らず、10 を超える文字が含まれる可能性があるという、提起された問題、OVER + FLOW = STACK に対する回答です。

  • 各文字が一意の数字を受け取るという規定がありますが、文字が多すぎるため、OVER + FLOW + STACK では不可能です。

Digitsテーブルに 1 つの列が含まれ、earch レコードに 1 から 9 (または必要に応じて 0 から 9) の整数が含まれる場合、このような方法が機能する可能性があります。

クロス結合はパフォーマンスの点でかなり厄介ですが、これは出発点になる可能性があります。

select
    top 5 
    O.num as O,
    V.num as V,
    E.num as E,
    R.num as R,
    F.num as F,
    L.num as L,
    W.num as W,
    S.num as S,
    T.num as T,
    A.num as A,
    C.num as C,
    K.num as K,
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num) as [OVER],
    (F.num * 1000 + L.num * 100 + O.num * 10 + W.num) as FLOW,
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num) + (F.num * 1000 + L.num * 100 + O.num * 10 + W.num) as OVER_plus_FLOW,
    (S.num * 10000 + T.num * 1000 + A.num * 100 + C.num * 10 + K.num) as STACK
from
    Digits as O
    cross join digits as V
    cross join digits as E
    cross join digits as R
    cross join digits as F
    cross join digits as L
    cross join digits as W
    cross join digits as S
    cross join digits as T
    cross join digits as A
    cross join digits as C
    cross join digits as K
where
    (O.num * 1000 + V.num * 100 + E.num * 10 + R.num)
    + (F.num * 1000 + L.num * 100 + O.num * 10 + W.num)
    = (S.num * 10000 + T.num * 1000 + A.num * 100 + C.num * 10 + K.num)

問題に対する私の理解に基づいて、複数の解決策があります。このコードが見つけた最初の 5 つを次に示します。

ここに画像の説明を入力

各文字をゼロに置き換えて安価な回答を得ることができるため、0 を削除しました (最初の質問のリビジョンに基づいて)。

テーブルはこれだけDigits

ここに画像の説明を入力

于 2013-02-27T04:46:23.077 に答える