Тема 19. Теория игр

19.04 Уменьшение количества камней

Вспоминай формулы по каждой теме
Решай новые задачи каждый день
Вдумчиво разбирай решения
ШКОЛКОВО.
Готовиться с нами - ЛЕГКО!
Подтемы раздела теория игр
Решаем задачи

Ошибка.
Попробуйте повторить позже

Задача 1#19950

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать в одной из куч два камня или уменьшить количество камней в куче в два раза (целочисленное деление). Чтобы делать ходы, у каждого игрока есть неограниченное количество камней. Количество камней не может быть отрицательно и игрок не может производить действие с кучей если она пуста. Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 12  . Победителем считается игрок, сделавший последний ход, т. е. первым получивший позицию, в которой в кучах будет 12  или меньше камней.

В начальный момент в первой куче было 25  камней, во второй куче — S  камней, 1 ≤ S ≤ 99  . Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника.

Известно, что Ваня выиграл своим первым ходом после неудачного первого хода Пети. Назовите минимальное значение S  , при котором это возможно.

Показать ответ и решение
from functools import lru_cache  
 
def moves(h):  
    a, b = h  
    res = []  
 
    if a - 2 >= 0:  
        res.append((a - 2, b))  
    if b - 2 >= 0:  
        res.append((a, b - 2))  
    if a > 0:  
        res.append((a // 2, b))  
    if b > 0:  
        res.append((a, b // 2))  
 
    return tuple(res)  
 
@lru_cache(None)  
def f(h):  
    if sum(h) <= 12:  
        return "END"  
    if any((f(x) == "END") for x in moves(h)):  
        return "P1"  
    if any((f(x) == "P1") for x in moves(h)):  
        return "V1"  
    if any((f(x) == "V1") for x in moves(h)):  
        return "P2"  
    if all((f(x) == "P2") for x in moves(h)):  
        return "V2"  
 
for s in range(1, 100):  
    h = 25, s  
    if f(h) == "V1":  
        print(s, "V1")

Ответ: 1

Ошибка.
Попробуйте повторить позже

Задача 2#19953

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать в одной из куч три камня или уменьшить количество камней в куче в 5 раз (целочисленное деление). Чтобы делать ходы, у каждого игрока есть неограниченное количество камней. Количество камней не может быть отрицательно и игрок не может производить действие с кучей если она пуста. Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 75  . Победителем считается игрок, сделавший последний ход, т. е. первым получивший позицию, в которой в кучах будет 75  или меньше камней.

В начальный момент в первой куче было 100  камней, во второй куче — S  камней, 50 ≤ S ≤ 100  . Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника.

Известно, что Петя выиграл своим первым ходом. Назовите минимальное значение S  , при котором это возможно.

Показать ответ и решение
from functools import lru_cache  
 
def moves(h):  
    a, b = h  
    res = []  
 
    if a - 3 >= 0:  
        res.append((a - 3, b))  
    if b - 3 >= 0:  
        res.append((a, b - 3))  
    if a > 0:  
        res.append((a // 5, b))  
    if b > 0:  
        res.append((a, b // 5))  
 
    return tuple(res)  
 
@lru_cache(None)  
def f(h):  
    if sum(h) <= 75:  
        return "END"  
    if any((f(x) == "END") for x in moves(h)):  
        return "P1"  
    if all((f(x) == "P1") for x in moves(h)):  
        return "V1"  
    if any((f(x) == "V1") for x in moves(h)):  
        return "P2"  
    if all((f(x) == "P2" or f(x) == "P1") for x in moves(h)):  
        return "V2"  
 
for s in range(50, 101):  
    h = 100, s  
    if f(h) == "P1":  
        print(s, "P1")

Ответ: 50

Ошибка.
Попробуйте повторить позже

Задача 3#23624

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать из одной из куч один камень или уменьшить количество камней в куче в два раза (если количество камней в куче нечётно, остаётся на 1  камень больше, чем убирается). Например, пусть в одной куче 6  , а в другой 9  камней; такую позицию мы будем обозначать (6,9)  . За один ход из позиции (6,9)  можно получить любую из четырёх позиций: (5,9)  , (3,9)  , (6,8)  , (6,5)  .

Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 40  . Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в кучах будет 40  или меньше камней.

В начальный момент в первой куче было 20  камней, во второй куче — S  камней, S > 20.

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит, описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по ней игрока, которые не являются для него безусловно выигрышными, т.е не гарантирующие выигрыш независимо от игры противника.

Известно, что Петя выигрывает в первый ход. Укажите максимальное значение S,  когда такая ситуация возможна.

Показать ответ и решение

Решение 1

Петя может выиграть первым ходом, если S = 21,...,40  . Для выигрыша достаточно вдвое уменьшить количество камней во второй куче. При больших значениях S  за один ход нельзя получить 40  или менее камней в двух кучах.

 

Решение 2

from functools import lru_cache
def moves(h):
    a, b = h
    m = []
    if a > 1:
        m += [((a + 1)//2, b), (a - 1, b)]
    if b > 1:
        m += [(a, (b + 1)//2), (a, b - 1)]
    return m

@lru_cache(None)
def f(h):
    if sum(h) <= 40:
        return ’END’
    if any(f(x) == ’END’ for x in moves(h)):
        return ’P1’

for i in range(19, 100):
    h = i, 20
    if f(h) == ’P1’:
        print(i)

Ответ: 40

Ошибка.
Попробуйте повторить позже

Задача 4#23693

Два игрока, Пинки и Вжик, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Пинки. За один ход игрок может убрать из одной из куч один камень или уменьшить количество камней в куче в два раза (если количество камней в куче нечётно, остаётся на 1  камень меньше, чем убирается). При любом из ходов кол-во камней в одной из куч должно измениться. Например, пусть в одной куче будет 6  камней, а в другой 9  камней; такую позицию мы будем обозначать (6,9)  . За один ход из позиции (6,9)  можно получить любую из четырёх позиций: (5,9),(6,8),(3,9),(6,4)  . Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 34  .

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в кучах будет 34  или менее камней. В начальный момент в первой куче было 22  камня, во второй куче S  камней, S > 12

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Найдите максимальное значение S  , при котором Вжик выигрывает своим первым ходом при любой игре Пинки.

Показать ответ и решение

Решение 1

Подпишем ячейки: A1  Start  , D1  P 1  . Поместим в ячейке A2  число 22  , а B2  наше значение S  . В ячейке C1  запишем формулу = A2 + B2  — там будет сумма камней во время старта

В ячейках E2 : F5  запишем все возможные пары куч, которые можно получить: в E2  поместим = A2 − 1  , в    F2  = B2  , в E3  поместим = (A2∕2)  (ЦЕЛОЕ возвращает как раз нужный нам результат деления), в F 3  = B2  , в E4  поместим = A2  , в F 2  = B2 − 1  , в E4  поместим = A2  , в F2  = (B2∕2)  . В ячейках столбца G  будем вести сумму куч (в G2  поместим = E2 + F 2  и растянем эту формулу на все пары куч).

В ячейке I2  запишем формулу = ((E2 : F 2)∕2)+ (E2 : F 2)  . Так мы получим сумму куч после самого аргессивного хода Вжика.

Условно окрасим в зеленый цвет ячейку I2  , если значение в ней меньше 35.

Постепенно перебирая значения ячейки B2  от 50 (например) вниз, заметим, что первый раз все ячейки результата выделяются зеленым при S = 26  . Значит, это максимальное значение, при котором выполняется условие.

Решение 2

from functools import cache
def moves(h):
    a, b = h
    mesi = []
    if a >= 1:
        mesi.append((a // 2, b))
        mesi.append((a - 1, b))
    if b >= 1:
        mesi.append((a, b // 2))
        mesi.append((a, b - 1))
    return mesi

@cache
def game(h):
    if sum(h) <= 34:
        return ’end’
    if any(game(x) == ’end’ for x in moves(h)):
        return ’win1’
    if all(game(x) == ’win1’ for x in moves(h)):
        return ’lose1’

for i in range(100, 11, -1):
    h = i, 22
    print(i, game(h))

Ответ: 26

Ошибка.
Попробуйте повторить позже

Задача 5#23711

Два игрока, Пупсень и Вупсень, играют в следующую игру. Перед игроками лежит куча камней. Игроки ходят по очереди, первый ход делает Пупсень. За один ход игрок может убрать из кучи один камень или убрать из кучи три камня. Например, имея кучу из 30 камней, за один ход можно получить кучу из 29 или 27 камней. Игра завершается в тот момент, когда количество камней в куче становится не более 11.

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в куче будет 11 или менее камней. В начальный момент в куче было S камней, S > 11.

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Известно, что Вупсень выиграл своим первым ходом после неудачного первого хода Пупсеня. Укажите максимальное значение S, когда такая ситуация возможна.

Показать ответ и решение
from functools import lru_cache
def moves(heap):
    m = []
    if heap > 0:
        m += [heap - 1]
    if heap > 2:
        m += [heap - 3]
    return m
@lru_cache(None)
def game(heap):
    if heap <= 11:
        return ’END’
    elif any(game(x) == ’END’ for x in moves(heap)):
        return ’WIN1’
    elif any(game(x) == ’WIN1’ for x in moves(heap)):
        return ’LOSE1’
    elif any(game(x) == ’LOSE1’ for x in moves(heap)):
        return ’WIN2’
    elif all(game(x) == ’WIN1’ or game(x) == ’WIN2’ for x in moves(heap)):
        return ’LOSE2’
for s in range(12, 100):
    print(s, game(s))
# или
from functools import lru_cache
def moves(heap):
    m = []
    if heap > 0:
        m += [heap - 1]
    if heap > 2:
        m += [heap - 3]
    return m
@lru_cache(None)
def game(heap):
    if heap <= 11:
        return 0
    steps = [game(x) for x in moves(heap)]
    if any(x % 2 == 0 for x in steps):
        return min(x for x in steps if x % 2 == 0) + 1
    return max(steps) + 1
                                                                                                     
                                                                                                     
for s in range(1, 100):
    print(s, game(s), [game(x) for x in moves(s)])

Ответ: 17

Ошибка.
Попробуйте повторить позже

Задача 6#23802

Два игрока, Наруто и Саске, играют в следующую игру. Перед игроками лежат три кучи кунаев. Игроки ходят по очереди, первый ход делает Наруто. За один ход игрок может убрать из одной из куч один кунай или уменьшить количество кунаев в куче в два раза (если количество кунаев в куче нечётно, остаётся на 1 кунай больше, чем убирается). При любом из ходов кол-во кунаев в одной из куч должно измениться. Например, пусть в первой куче будет 6 кунаев, во второй куче 7 кунаев, а в третьей 8 кунаев; такую позицию мы будем обозначать (6, 7, 8). За один ход из позиции (6, 7, 8) можно получить любую из шести позиций: (5, 7, 8), (6, 6, 8), (6, 7, 7), (3, 7, 8), (6, 4, 8), (6, 7, 4). Игра завершается в тот момент, когда суммарное количество кунаев в кучах становится не более 32.

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в кучах будет 32 или менее кунаев. В начальный момент в первой и второй куче было 11 кунаев, в третьей куче S кунаев, S > 11  .

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Известно, что Саске выиграл своим первым ходом после неудачного первого хода Наруто. Укажите максимальное значение S, когда такая ситуация возможна.

Показать ответ и решение
from functools import lru_cache


@lru_cache(None)
def f(first_heap, second_heap, third_heap, c=0):
    if first_heap + second_heap + third_heap <= 32:
        return 0
    if c > 4:
        return 123123
    moves = []
    if first_heap > 1:
        moves.append(f(first_heap - 1, second_heap, third_heap, c + 1))
        moves.append(f((first_heap + 1) // 2, second_heap, third_heap, c + 1))
    if second_heap > 1:
        moves.append(f(first_heap, second_heap - 1, third_heap, c + 1))
        moves.append(f(first_heap, (second_heap + 1) // 2, third_heap, c + 1))
    if third_heap > 1:
        moves.append(f(first_heap, second_heap, third_heap - 1, c + 1))
        moves.append(f(first_heap, second_heap, (third_heap + 1) // 2, c + 1))

    petya_win = [i for i in moves if i <= 0]
    if petya_win:
        return -max(petya_win) + 1
    else:
        return -max(moves)


for i in range(11, 100):
    if f(11 - 1, 11, i) == 1 or f((11 + 1) // 2, 11, i) == 1 or f(11, 11-1, i) == 1 or \
            f(11, (11 + 1) // 2, i) == 1 or f(11, 11, i - 1) == 1 or f(11, 11, (i + 1) // 2) == 1:
        print(i)

Ответ: 40

Ошибка.
Попробуйте повторить позже

Задача 7#26098

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать из одной из куч один камень или уменьшить количество камней в куче в два раза (если количество камней в куче нечётно, остаётся на 1 камень больше, чем убирается). Например, пусть в одной куче 6, а в другой 9 камней; такую позицию мы будем обозначать (6, 9). За один ход из позиции (6, 9) можно получить любую из четырёх позиций: (5, 9), (3, 9), (6, 8), (6, 5). Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 32. Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в кучах будет 32 или меньше камней. В начальный момент в первой куче было 10 камней, во второй куче – S  камней, S  > 22.

 

Найдите значение S  , при котором Ваня выигрывает своим первым ходом при любой игре Пети.

Показать ответ и решение
from functools import lru_cache

def moves(h):
    a, b = h
    if a > 1 and b > 1:
        return (a - 1, b), (a, b - 1), (a // 2 + (a % 2), b), (a, b // 2 + (b % 2))
    if a > 1:
        return (a - 1, b), (a, b - 1), (a // 2 + (a % 2), b)
    if b > 1:
        return (a - 1, b), (a, b - 1), (a, b // 2 + (b % 2))
    return (a - 1, b), (a, b - 1)

@lru_cache(None)
def f(h):
    if sum(h) <= 32:
        return ’END’
    if any(f(x) == ’END’ for x in moves(h)):
        return ’WIN1’
    if all(f(x) == ’WIN1’ for x in moves(h)):
        return ’LOSE1’

for i in range(23, 100):
    h = i, 10
    if f(h) == ’LOSE1’:
        print(i)

Ответ: 45

Ошибка.
Попробуйте повторить позже

Задача 8#30379

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежит куча камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать из кучи один камень или убрать из кучи три камня. Например, имея кучу из 30  камней, за один ход можно получить кучу из 29  или 27  камней. Игра завершается в тот момент, когда количество камней в куче становится не более 7.

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в куче будет 7  или менее камней. В начальный момент в куче было S  камней, S > 7.

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Укажите максимальное значение S  , при котором Петя мог выиграть первым или вторым ходом, но совершил неверный ход и выиграл Ваня.

Показать ответ и решение

Решение руками

Неудачный ход – ход при котором игрок мог победить, но отдал победу противнику. Поэтому для начала найдем значения S  , при которых Петя мог победить за 1 или 2 хода.

Рассмотрим ситуацию, когда Петя сделал один ход. Чтобы получить число 7 есть всего 2 возможных хода: убрать из кучи один камень или убрать из кучи три камня. Для этих ходов подойдут значения S = 8  и S = 10  .

Теперь рассмотрим ситуацию, когда Петя сделал два хода. Так как мы знаем, что из S = 8  и S = 10  можно победить за 1 ход, то все ходы Вани должны приводить в эти значения, тогда перед ходом Вани S = 11  . И следовательно, чтобы Петя победил вторым ходом перед началом игры S = 12  и S = 14  .

Рассмотрим S = 14  . Первым ходом Петя делает неудачный ход – убирает 1 камень, S = 13  – из этой позиции нельзя победить за один ход, поэтому этот вариант не подходит.

Рассмотрим S = 12  . Первым ходом Петя делает неудачный ход – убирает 3 камня, S = 9  – из этой позиции можно победить за один ход, поэтому этот вариант подходит.

Решение программой

from functools import lru_cache

@lru_cache(None)
def game(heap):  # Функция игры
    if heap <= 7:  # Если камней в кучах стало меньше 7
        return 0  # Прекращаем игру
    moves = [game(heap - 1), game(heap - 3)]  # Генерация всех возможных ходов
    petya_win = [i for i in moves if i <= 0]
    if petya_win: # если в данной позиции есть выигрыш Пети
        return -max(petya_win) + 1
    else: # если в данной позиции выигрыш Вани
        return -max(moves)

for i in range(8, 100):
    if game(i) == 1 or game(i) == 2:  # Если Петя мог победить своим 1ым или 2м ходом

        # Для неудачного хода Пети нужно вручную сделать за него ходы от взятого s
        # и запустить функцию с изменнённым значением кучи, чтобы в хотя бы одном из ходов Петя ошибся.
        # Таким образом, Ваня станет первым ходившим игроком для функции,
        # и в итоге нужно будет получить значение 1 для победы Вани первым ходом после неудачного хода Пети.

        vanya_win = False  # Переменная-флаг, отвечающая за победу Вани (изначально Ваня не побеждает)
        if game(i - 1) == 1:  # Если при ходе -1 в итоге победит Ваня
            vanya_win = True
        if game(i - 3) == 1:  # Если при ходе -3 в итоге победит Ваня
            vanya_win = True

        if vanya_win:  # Если в итоге Ваня победил
            print(i)

Ответ: 12

Ошибка.
Попробуйте повторить позже

Задача 9#30382

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежат две кучи камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может убрать из одной из куч один камень или уменьшить количество камней в куче в два раза (если количество камней в куче нечётно, остаётся на 1  камень меньше, чем убирается). При любом из ходов кол-во камней в одной из куч должно измениться. Например, пусть в одной куче будет 6  камней, а в другой    9  камней; такую позицию мы будем обозначать (6,9).  За один ход из позиции (6,9)  можно получить любую из четырёх позиций: (5,9),(6,8),(3,9),(6,4).  Игра завершается в тот момент, когда суммарное количество камней в кучах становится не более 12.

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в кучах будет 12  или менее камней. В начальный момент в первой куче было 9  камня, во второй куче S  камней, S > 3

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Найдите минимальное значение S,  при котором Ваня выигрывает своим первым ходом при любой игре Пети.

 

Показать ответ и решение

Решение руками

Очевидно, что при S ≤ 8  Петя выигрывает своим первым ходом (уменьшением кучи, в которой лежит 9  камней, в два раза). Значит при S = 9  Петя не сможет победить своим первым ходом, зато это сможет сделать Ваня. Ответ 9  .

 

Решение Excel

PIC

Создадим табличку, первый столбец которой назовём Старт, четвёртый Петя, а седьмой — Ваня.

В ячейку B4  запишем 9  , а в D4 запишем формулу =СУММ(B4:C4).

Так как Ване нужно победить первым ходом, то выгоднее всего ходить самым агрессивным ходом — делением на два. В ячейку H4  запишем формулу =ЦЕЛОЕ(МАКС(E4:F4)/2), в I4  — =МИН(E4:F4).

В ячейку J4 запишем формулу =СУММ(H4:I4), скопируем и вставим её в следующую клеточку.

В E4  запишем =B4-1, в F4− =C4, а в G4  — =СУММ(E4:F4).

Добавим условное форматирование. Выделим суммы, которые относятся к Пете и затем в разделе Главная выберем условное форматирование ⇒ Правила выделения ячеек ⇒ Меньше…, в открывшемся окошке записываем 13  и выбираем красный цвет. Выделим сумму, которая относится к старту, сделаем её зелёной по аналогии с суммой после хода Пети. То же самое сделаем с суммой, которая относится к Ване.

Скопируем полученную таблицу и вставим её три раза, каждый раз чуть ниже предыдущей. Заменим первые ходы Пети, чтобы не было повторов.

В начальную позицию запишем 9  и начнём подставлять значения в ячейку C4  , пока все суммы камней после хода Вани не станут зелёными.

 

Решение программой

from functools import lru_cache

@lru_cache(None)
def game(first_heap, second_heap):  # Функция игры
    if first_heap + second_heap <= 12:  # Если камней в кучах стало меньше 12
        return 0  # Прекращаем игру
    moves = [game(first_heap, second_heap // 2), game(first_heap // 2, second_heap),
             game(first_heap - 1, second_heap),game(first_heap, second_heap - 1)]  # Генерация всех возможных ходов
    petya_win = [i for i in moves if i <= 0]
    if petya_win: # если в данной позиции есть выигрыш Пети
        return -max(petya_win) + 1
    else: # если в данной позиции выигрыш Вани
        return -max(moves)

for i in range(4, 20):
    # если в данной позиции возможен выигрыш Вани первым ходом
    if game(9,i) == -1:
        print(i)
        break

Ответ: 9

Ошибка.
Попробуйте повторить позже

Задача 10#30397

Два игрока, Петя и Ваня, играют в следующую игру. Перед игроками лежит куча камней. Игроки ходят по очереди, первый ход делает Петя. За один ход игрок может либо убрать из кучи половину камней, если количество камней в куче делится на два, иначе убрать из кучи два камня, либо убрать из кучи две трети камней, если количество камней в куче делится на три, иначе убрать из кучи три камня. Например, пусть в куче будет 6  камней. Тогда за один ход можно получить кучу из 3  или 2  камней. Игра завершается в тот момент, когда количество камней в куче становится меньше или равно 2.

Победителем считается игрок, сделавший последний ход, то есть первым получивший позицию, в которой в куче будет 2  и менее камней. В начальный момент в куче было S  камней S > 2  .

Будем говорить, что игрок имеет выигрышную стратегию, если он может выиграть при любых ходах противника. Описать стратегию игрока — значит описать, какой ход он должен сделать в любой ситуации, которая ему может встретиться при различной игре противника. В описание выигрышной стратегии не следует включать ходы играющего по этой стратегии игрока, не являющиеся для него безусловно выигрышными, т. е. не являющиеся выигрышными независимо от игры противника.

Найдите максимальное значение S,  при котором Ваня может выиграть своим первым ходом после неудачного хода Пети, который мог выиграть своим первым ходом.

Показать ответ и решение

Решение руками

Для начала найдем значения S  , при которых Петя мог победить за 1 ход. Чтобы получить число 2, есть всего 4 возможных хода: убрать половину камней, убрать два камня, убрать две трети камней, убрать три камня. Для всех этих ходов подойдут следующие значения S : 3,4,5,6.  Значит нужно рассмотреть только 4 значения S  и выбрать максимальное, чтобы Ваня мог победить при неудачном ходе Пети. Рассмотрим S = 6.  Первым ходом Петя делает неудачный ход делением на 2 (так как 6 делится на 2) в S = 3,  после чего Ваня например убирает из кучи две трети камней, создавая этим позицию S = 1,  в которой он побеждает.

Решение программой

from functools import lru_cache


@lru_cache(None)
def game(heap):  # Функция игры

    if heap <= 2:  # Если куча меньше или равна 2
        return 0  # Возвращаем стартовое значение 0

    # Список для возможных ходов,
    # которые нужно добавить в зависимости от условий
    steps = []
    # 1 Условие
    if heap % 2 == 0:
        steps += [game(heap // 2)]  # Убираем половину
    else:
        steps += [game(heap - 2)]  # Убираем 2 камня
    # 2 Условие
    if heap % 3 == 0:
        steps += [game(heap // 3)]  # Убрать две трети равносильно оставить одну треть
    else:
        steps += [game(heap - 3)]  # Убираем 3 камня

    petya_win = [x for x in steps if x <= 0]  # Выигрышные позиции для пети

    if petya_win:  # Если такие значения есть
        return -max(petya_win) + 1
    return -max(steps)


for s in range(3, 100):
    if game(s) == 1:  # Если Петя мог победить своим 1ым ходом

        # Для неудачного хода Пети нужно вручную сделать за него ходы от взятого s
        # и запустить функцию с изменнённым значением кучи, чтобы в хотя бы одном из ходов Петя ошибся.
        # Таким образом, Ваня станет первым ходившим игроком для функции,
        # и в итоге нужно будет получить значение 1 для победы Вани первым ходом после неудачного хода Пети.

                                                                                                     
                                                                                                     
        vanya_win = False  # Переменная-флаг, отвечающая за победу Вани (изначально Ваня не побеждает)
        if s % 2 == 0:
            if game(s // 2) == 1:  # Если при ходе //2 в итоге победит Ваня
                vanya_win = True
        else:
            if game(s - 2) == 1:  # Если при ходе -2 в итоге победит Ваня
                vanya_win = True
        if s % 3 == 0:
            if game(s // 3) == 1:  # Если при ходе //3 в итоге победит Ваня
                vanya_win = True
        else:
            if game(s - 3) == 1:  # Если при ходе -3 в итоге победит Ваня
                vanya_win = True

        if vanya_win:  # Если в итоге Ваня победил
            print(s)

Ответ: 6
Рулетка
Вы можете получить скидку в рулетке!