Задание №20 — Теория игр
Для игры, описанной в предыдущем задании, найдите два таких значения S, при которых у Пети есть выигрышная стратегия, причём одновременно выполняются два условия:
– Петя не может выиграть за один ход;
– Петя может выиграть своим вторым ходом независимо от того, как будет ходить Ваня.
Найденные значения запишите в ответе в порядке возрастания.
Правильный ответ
31 34
Пояснение
Решение:
Напомним условия игры: перед игроками две кучи камней, за ход можно добавить в одну из куч (по своему выбору) один камень либо увеличить количество камней в одной из куч вдвое; игра заканчивается, когда суммарное количество камней в кучах становится не менее . Начальная позиция — , первым ходит Петя.
Позицию будем оценивать с точки зрения игрока, который ходит из неё. Обозначим: В1 — из позиции можно выиграть первым же ходом; П1 — любой ход не заканчивает игру и переводит соперника в В1 (то есть ходящий проигрывает следующим ходом соперника); В2 — позиция не В1, но есть ход, переводящий соперника в П1, то есть ходящий выигрывает ровно вторым своим ходом при любой игре соперника.
. Сразу Петя выиграть не может (). Петя удваивает первую кучу — получается позиция , игра не окончена. Теперь любой ход Вани проигрышный:
- — Петя удваивает вторую кучу: ;
- — Петя удваивает вторую кучу: ;
- — Петя удваивает вторую кучу: ;
- — Петя добавляет камень: .
. Сразу Петя выиграть не может (). Петя добавляет камень в первую кучу — получается позиция , игра не окончена. Теперь любой ход Вани проигрышный:
- — Петя удваивает вторую кучу: ;
- — Петя удваивает вторую кучу: ;
- — Петя удваивает вторую кучу: ;
- — Петя добавляет камень: .
Полный перебор удобнее доверить программе:
N = 77
def moves(p):
a, b = p
return [(a + 1, b), (a, b + 1), (2 * a, b), (a, 2 * b)]
def over(p): # игра закончена
return p[0] + p[1] >= N
def win1(p): # В1: выигрыш своим первым ходом
return any(over(q) for q in moves(p))
def lose1(p): # П1: любой ход отдаёт победу сопернику
return all(not over(q) and win1(q) for q in moves(p))
def win2(p): # В2: выигрыш вторым ходом, но не первым
return not win1(p) and any(not over(r) and lose1(r) for r in moves(p))
print(*[s for s in range(1, 70) if win2((7, s))][:2]) # два наименьшихОтвет: 31 34