Решение крипто-арифметической головоломки с реляционной базой данных

Скажем, вам дали крипто-арифметическую головоломку:

ОТПРАВИТЬ + БОЛЬШЕ = ДЕНЬГИ

Цель состоит в том, чтобы заменить буквы цифрами (0-9), чтобы сложение получилось.

Я понимаю, как подойти к проблеме математически, но не знаю, как решить ее с помощью реляционной базы данных.

Какую схему следует разработать для решения этой проблемы?

Как будет выглядеть SQL-запрос, который попытается решить эту проблему?

EDIT: есть некоторые ограничения:

  1. Один и тот же номер должен использоваться для данной буквы повсюду. Например, если вы угадываете «5» для буквы E, то E должна получить значение «5» во всех местах, где она встречается.
  2. Разным буквам должны присваиваться разные числа, например, вы не можете присвоить «4» как Е, так и М.
  3. Ни одно из чисел (слов) не может иметь ведущие нули

person wilco    schedule 27.02.2013    source источник
comment
Есть ли максимальное ограничение на длину слов?   -  person    schedule 27.02.2013
comment
За один раз нужно будет решить только одну головоломку, поэтому таблицы могут быть созданы/изменены специально для этой попытки. Все головоломки будут иметь формат длина (4) + длина (4) = длина (5).   -  person wilco    schedule 27.02.2013
comment
Ваше первое редактирование невозможно, там более 10 разных букв. Каждый не может иметь свою цифру   -  person Brian Webster    schedule 27.02.2013
comment
Буквы не перемножаются. Они объединяются, чтобы сформировать 1 длинное целое число. O=1,V=2,E=3,R=4 ==› 1234   -  person wilco    schedule 27.02.2013
comment
Это условие может быть невозможным для уравнения, которое я предоставил, потому что я изменил фактическую проблему только для StackOverflow. Фактическая проблема заключается в том, что ОТПРАВИТЬ + ЕЩЕ = ДЕНЬГИ   -  person wilco    schedule 27.02.2013
comment
@BrianWebster - будет ли новое уравнение выглядеть так же или вы подошли бы к нему по-другому, если бы это условие было невозможным?   -  person wilco    schedule 27.02.2013
comment
Хорошо, я опубликовал второй ответ, так как эти две проблемы совершенно уникальны.   -  person Brian Webster    schedule 27.02.2013
comment
Извини за это! Я и не подозревал, что у моего нового уравнения столько значений!   -  person wilco    schedule 27.02.2013
comment
Слишком поздно для этого поста, но у меня есть рассуждения на основе множеств и реализация PosgreSQL на моем сайте damirsystems. .com/?p=713   -  person Damir Sudarevic    schedule 09.01.2017


Ответы (2)


Это решает другую проблему, поставленную пользователем.

ОТПРАВИТЬ + БОЛЬШЕ = ДЕНЬГИ, где каждый символ имеет уникальную цифру, и ни одно слово не начинается с нуля.

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 вместо соображений скорости.

Вот предложение FROM + WHERE без сумасшедших предложений ON. На моем сервере это работает НАМНОГО медленнее.

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
person Brian Webster    schedule 27.02.2013

Автор ставит две разные задачи.

Это решает поставленную проблему: ПЕРЕД + ПОТОК = СТЕК, где каждый символ не обязательно имеет уникальную цифру и может быть задействовано более 10 символов

  • Существует условие, что каждый символ получает уникальную цифру, но это невозможно для OVER + FLOW + STACK, так как букв слишком много.

Нечто подобное может работать, когда таблица Digits содержит один столбец, где запись поиска содержит целое число от 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

введите здесь описание изображения

person Brian Webster    schedule 27.02.2013