当前位置:嗨网首页>书籍在线阅读

06-字谜(SEND+MORE=MONEY)

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

3.5 字谜(SEND+MORE=MONEY)

字谜(SEND+MORE=MONEY)是一种数字密码谜题,目标是要找到替换字母的数字使数学式成立。该问题中的每个字母都代表一个数字(0~9)。同一个数字只会用一个字母来表示。如果字母重复出现,则表示最后的解中也有数字重复。

如果要人工求解字谜问题,那么把单词排成竖式会很有用。

  SEND
 +MORE
=MONEY

只要运用一点代数知识和直觉,人工求解一定是可行的。但一个相当简单的计算机程序可以通过蛮力(brute-forcing)试探大量可能的结果来更快地求解。下面把SEND + MORE = MONEY谜题表示为约束满足问题,具体代码如代码清单3-16所示。

代码清单3-16 send_more_money.py

from csp import Constraint, CSP
from typing import Dict, List, Optional
class SendMoreMoneyConstraint(Constraint[str, int]):
    def __init__(self, letters: List[str]) -> None:
       super().__init__(letters)
       self.letters: List[str] = letters
    def satisfied(self, assignment: Dict[str, int]) -> bool:
        # if there are duplicate values, then it's not a solution
        if len(set(assignment.values())) < len(assignment):
            return False
        # if all variables have been assigned, check if it adds correctly
        if len(assignment) == len(self.letters):
            s: int = assignment["S"]
            e: int = assignment["E"]
            n: int = assignment["N"]
            d: int = assignment["D"]
            m: int = assignment["M"]
            o: int = assignment["O"]
            r: int = assignment["R"]
            y: int = assignment["Y"]
            send: int = s * 1000 + e * 100 + n * 10 + d
            more: int = m * 1000 + o * 100 + r * 10 + e
            money: int = m * 10000 + o * 1000 + n * 100 + e * 10 + y
            return send + more == money
        return True # no conflict

SendMoreMoneyConstraintsatisfied() 方法完成了一些任务。首先,它检查是否存在多个字母代表同一个数字的情况,如果存在则说明那是一个无效解,返回 False 。然后,它检查是否已给所有字母赋值,如果是则会检查已有赋值是否符合公式(SEND+MORE=MONEY),如果符合则说明解已找到,返回 True ,否则返回 False 。最后,如果尚未给所有字母赋值,则返回 True ,这是为了保证能继续求解。

下面试着运行一下代码清单3-17中的代码。

代码清单3-17 send_more_money.py(续)

if __name__ == "__main__":
    letters: List[str] = ["S", "E", "N", "D", "M", "O", "R", "Y"]
    possible_digits: Dict[str, List[int]] = {}
    for letter in letters:
        possible_digits[letter] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    possible_digits["M"] = [1]  # so we don't get answers starting with a 0
    csp: CSP[str, int] = CSP(letters, possible_digits)
    csp.add_constraint(SendMoreMoneyConstraint(letters))
    solution: Optional[Dict[str, int]] = csp.backtracking_search()
    if solution is None:
        print("No solution found!")
    else:
        print(solution)

注意,这里会预先给字母M赋上答案,这是为了确保M的解中不会包含0,因为约束里没有规定数字不能从0开始。大家可以去试试,看看不做此预先赋值会发生什么情况。

结果将如下所示:

{'S': 9, 'E': 5, 'N': 6, 'D': 7, 'M': 1, 'O': 0, 'R': 8, 'Y': 2}