Рассмотрим следующую постановку задачи:
Получив начальное число, вы и ваш друг по очереди вычитаете из него идеальный квадрат. Первый, кто доберется до нуля, побеждает. Например:
Начальное состояние: 37
Игрок1 вычитает 16. Состояние: 21
Игрок2 вычитает 8. Состояние: 13
Игрок1 вычитает 4. Состояние: 9
Player2 вычитает 9. Состояние: 0
Player2 выигрывает!
Напишите программу, которая при заданном начальном состоянии возвращает оптимальный ход, то есть тот, который гарантированно приведет к победе в игре. Если никакое возможное движение не может привести вас к выигрышному состоянию, верните -1.
Эта проблема может быть решена в псевдополиномиальное время с помощью динамического программирования. Идея состоит в том, чтобы просто заполнить массив длиной n (где n - начальное состояние) снизу оптимальными ходами или -1, если ни один ход не приводит к победе. Это заняло бы O (n * sqrt (n)), так как для каждого числа мы должны рассмотреть вычитание каждого возможного совершенного квадрата, меньшего его (их есть ~ sqrt (n)). Однако это псевдополиномиальная сложность среды выполнения, поскольку среда выполнения фактически экспоненциально масштабируется по отношению к размеру входных данных в двоичном формате (число битов, используемых для представления числа).
Кто-нибудь может придумать полиномиальный алгоритм для решения этой проблемы? Если нет, то может ли это быть NP-Complete? Почему?