【问题标题】:Solving a Crypt-Arithmetic Puzzle with Relational Database使用关系数据库解决密码算术难题
【发布时间】:2013-02-27 04:25:26
【问题描述】:

假设给你一个密码算术难题:

发送 + 更多 = 钱

我们的目标是用数字 (0-9) 代替字母,这样加法就可以了。

我了解如何以数学方式解决问题,但我不确定如何使用关系数据库解决此问题。

如何设计架构来解决这个问题?

尝试解决此问题的 SQL 查询看起来如何?

编辑: 有一些限制:

  1. 给定的字母应始终使用相同的数字。例如,如果 你猜字母 E 是“5”,那么 E 应该在它的所有地方得到值“5” 发生。
  2. 不同的字母应该有不同的数字,例如,您不能将“4”分配给两者 E 和 M。
  3. 所有数字(单词)都不能有任何前导零

【问题讨论】:

  • 单词的长度有最大限制吗?
  • 一次只能解决一个难题,因此可以专门为该尝试创建/修改表。谜题的格式都是长度(4)+长度(4)=长度(5)
  • 您的第一次编辑是不可能的,有超过 10 个不同的字母。每个都不能有自己的数字
  • 字母不相乘。它们连接起来形成 1 个长整数。 O=1,V=2,E=3,R=4 ==> 1234
  • 对于我提供的等式,该规定可能是不可能的,因为我只是为 StackOverflow 更改了实际问题。实际问题是 SEND + MORE = MONEY

标签: sql relational-database cryptarithmetic-puzzle


【解决方案1】:

这回答了用户提出的另一个问题。

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

【讨论】:

    【解决方案2】:

    作者提出了两个不同的问题。

    这回答了提出的问题,OVER + FLOW = STACK,其中每个字符不一定有唯一的数字,可能涉及超过 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-04
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多