Оцените минимаксное дерево

16

Алиса и Боб играют в небольшую игру. Сначала они рисуют дерево из корневого узла (обозначенного жирной точкой), без внутренних узлов, с номерами на листьях. Любой узел может иметь любое количество детей.

дерево

Мы начинаем с корня, и первым играем Алиса (A). Она должна выбрать одного из детей текущего узла. Затем очередь Боба, и он аналогичным образом выбирает дочерний узел. Это продолжается до тех пор, пока не будет достигнут листовой узел.

Когда достигнут конечный узел, игра заканчивается. Цель Алисы - закончить узел как можно большим значением, а цель Боба - закончить узел как можно меньшим значением.

Если задано дерево в форме вложенного массива, верните значение листа, который будет достигнут, если Алиса и Боб будут играть идеально.


Примеры:

18: [[67, [[100, [[67, 47], [86], 21, 16], [[46, [14], 35, 85], [71, [18, 63, 69], 99, 22], 3]]], [[18, 32, 42, 80]], [[36, 70], [86, 53, 46, 59], [[41], 86, 35]]], 3]
60: [[[84, 35], [44, 60]], [[24, 98], [16, 21]]]
58: [[53, 77], [58, [82, 41]], 52]
59: [[93, [100, 53], 58, 79], [63, 94, 59], [9, [55, 48]], [40, 10, 32]]
56: [[20, 10, [[[89, 22, 77, 10], 55], [24, 28, 30, 63]]], [[49, 31]], 17, 56]
0: [0]

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


Самый короткий код в байтах побеждает.

orlp
источник
Я узнаю это!
Коннор Белл,

Ответы:

2

Желе , 7 байт

N߀¬¡ṂN

Попробуйте онлайн! или проверьте все контрольные примеры .

Это использует алгоритм из ответа @ xnor . Для сравнения, более простой подход, который поочередно вычисляет минимумы и максимумы, весит 8 байтов :

߀¬¡€Ṃ€Ṁ

Как это устроено

N߀¬¡ṂN  Main link. Argument: x (array or integer)

N        Negate. For an array, this negates all integers in it.
   ¬     Logical NOT. For an array, this applies to all integers in it.
    ¡    Apply the second link to the left once if ¬ returned an array or 1, or not
         at all if it returned 0.
 ߀      Recursively call the main link on all elements at depth 1 of -x.
         If -x == 0, € will cast 0 to range before mapping ß over it. 
         Since the range of 0 is [], mapping ß over it simply yields [].
     Ṃ   Minimum.
         For an integer, Ṃ simply returns the integer. For [], Ṃ returns 0.
      N  Negate the minimum.
Деннис
источник
8

Python 2, 53 байта

f=lambda l,c=1:c*l if l<[]else-min(f(x,-c)for x in l)

Основной вопрос состоит в том , чтобы выбрать между maxи minкаждый слой. Используя тот факт, что max(l) == -min([-x for x in l])мы вместо этого отрицаем каждый второй слой и повторяем с -min. Чтобы свести на нет каждый второй слой, мы передаем множитель, cкоторый чередуется, +1и -1, когда мы достигаем листа, мы корректируем его значение с помощью множителя. Мы понимаем, что находимся на листе через условие l<[], так как Python 2 рассматривает числа как списки.

Трудно сократить else/ifтроичный, потому что любая ветвь может дать значение Truthy (ненулевое) или Falsey (ноль).

XNOR
источник
1

JavaScript (ES6), 53 байта

f=(a,s=1)=>a.map?s*Math.max(...a.map(b=>s*f(b,-s))):a

Использует аналогичный подход к ответу @ xnor. Если числа ненулевые, то только 49 байтов:

f=(a,s=1)=>+a||s*Math.max(...a.map(b=>s*f(b,-s)))
Нил
источник
1

Pyth, 21 байт

M?sIG*GH_hSmgd_HGLgb1

Мой первый ответ Pyth! Спасибо Деннису за помощь :).

M                      # define a binary function (G, H)
 ?sIG                  # if G (first argument) is the same with s applied
                       # (check if it's an integer, so, a leaf node)
     *GH               # in such a case, calculate G*H
        _              # negation
         hS            # take the first element of the sorted list (that's the min)
           mgd_HG      # map over G, applying ourself (g) recursively,
                       # with the current lambda's value (d)
                       # and the negation of H
                 Lgb1  # Define a unary function to call our previous
                       # one with the correct base argument (1)
Вен
источник
У этой карты более короткий синтаксис: mgd_Hможет быть gR_H. Кроме того, вместо определения функции вы можете взять ввод с помощью Qи заменить Lgb1на gQ1.
lirtosiast
1

Mathematica, 13 байт

-Min[#0/@-#]&

или эквивалентно

Max[-#0/@-#]&

Это оценивает безымянную функцию, которая берет дерево и возвращает результат.

Это также по сути то же самое, что и решение xnor: на каждом уровне мы меняем знак списка и результат и используем его Minдо конца. Это оказалось невероятно гольфом в Mathematica, потому что:

  • Minможет принимать либо отдельные номера или списки или даже несколько списков. Это просто дает вам минимальное значение по всем своим аргументам. Это означает, что он работает как со списками, так и с листьями (где он просто возвращает лист).
  • /@это сокращение для Mapочень общей функции высшего порядка в Mathematica. Он не просто отображает функцию по спискам, он может отображать их по любому выражению. Числа являются таким выражением, но они не содержат элементов для отображения. Это означает, что мы можем безопасно сопоставить любую функцию с числами, что никак не влияет на число.

Обе эти вещи вместе означают , что мы можем написать код без какого - либо условного, так Minи Mapоперации нет-OPS по номерам, а впоследствии два отрицаний отменить так , что функция становится тождественной , когда данный номер.

Наконец, благодаря#0 этому в Mathematica можно писать безымянные рекурсивные функции, что экономит еще несколько байтов.

Мартин Эндер
источник
0

Рубин, 46 байт

Использовал трюк @ xnor с minдля чередования между макс и мин.

f=->n,a=1{n==[*n]?-n.map{|c|f[c,-a]}.min: a*n}
Значение чернил
источник