Шаг 45.
Задачи ComputerScience на Python.
Задачи с ограничениями. SEND + MORE = MONEY

    На этом шаге мы рассмотрим решение этой головоломки.

    SEND + MORE = MONEY - это криптоарифметическая головоломка, где нужно найти такие цифры, которые, будучи подставленными вместо букв, сделают математическое утверждение верным. Каждая буква в задаче представляет одну цифру от 0 до 9. Никакие две разные буквы не могут представлять одну и ту же цифру. Если буква повторяется, это означает, что цифра в решении также повторяется.

    Чтобы проще было решить эту задачку вручную, стоит выстроить слова в столбик:

    SEND
+
    MORE
   ------
   MONEY

    Задача легко решается вручную, потребуется лишь немного алгебры и интуиции. Но довольно простая компьютерная программа поможет сделать это быстрее, используя множество возможных решений. Представим SEND + MORE = MONEY как задачу с ограничениями.

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 len(set(assignment.values())) < len(assignment):
            return False
        # если все переменные назначены, проверяем, правильна ли сумма
        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  # нет противоречий

    Метод SendMoreMoneyConstraint satisfied() выполняет несколько действий. Во-первых, он проверяет, соответствуют ли разные буквы одинаковым цифрам. Если это так, то решение неверно и метод возвращает False. Затем метод проверяет, всем ли буквам назначены цифры. Если это так, то он проверяет, является ли формула SEND + MORE = MONEY корректной с данным присваиванием. Если да, то решение найдено и метод возвращает True. В противном случае возвращается False. Наконец, если еще не всем буквам присвоены цифры, то возвращается True. Это сделано для того, чтобы после получения частичного решения работа продолжалась.

   

Попробуем это запустить:
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]  # мы не принимаем ответы, начинающиеся с 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("Решение не найдено!")
    else:
        print(solution)
Архив с файлом можно взять здесь.

    Вы, вероятно, заметили, что мы предварительно задали значение для буквы М. Это сделано для того, чтобы исключить ответ, в котором М соответствует 0, потому что, если подумать, ограничение не учитывает, что число не может начинаться с нуля. Но попробуйте выполнить программу без этого заранее назначенного ответа.

    Решение должно выглядеть примерно так:

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

    На следующем шаге мы рассмотрим размещение элементов на печатной плате.




Предыдущий шаг Содержание Следующий шаг