Как решается «проблема выбора пиццы» с использованием методов динамического программирования?

9

У Винклера проблема со сбором пиццы:

  • Круглый nкусочек пиццы из кусочков, где кусочек iимеет площадь, S_iт.е. площадь отличается для каждого кусочка пирога.
  • Пожиратели Алиса и Боб по очереди выбирают кусочки, но было бы глупо создавать несколько пробелов в круговой диаграмме (считайте, что это не разрешено).
    • Таким образом, каждый едок ограничен взятием одного из двух кусочков, прилегающих к открытой области. Алиса идет первой, и оба едока ищут как можно больше пирога.

Как алгоритм динамического программирования определяет, сколько пирога ест Алиса, если Алиса и Боб играют идеально, чтобы максимизировать потребление пиццы?

Мое понимание:

В общей проблеме DP мы продолжаем поиск подзадач, которые можно визуализировать с помощью дерева рекурсии или, более точно, с помощью DAG. Здесь я не нахожу никакой возможности найти подзадачи здесь.

Здесь, для данного набора S_i, нам нужно максимизировать площадь кусочков, которые съела Алиса. Это будет зависеть от выбора перестановки ломтиков пиццы из (n-1) перестановок. Выбор максимальной области среза из двух вариантов, доступных через каждые n \ 2 оборота, которые получает Алиса, даст нам общую площадь среза для перестановки. Нам нужно найти площадь среза для всех таких перестановок. И тогда максимум из них.

Может кто-нибудь помочь мне, как идти вперед?

Амит Шехар
источник

Ответы:

5

Начните с рассмотрения ломтиков, только что помещенных в ряд, и вы можете выбрать один из двух концов. В этом случае , предполагающем , что ваша очередь выбрала это ясно , что pizzaAmount(slices)это

  1. Если пиццы не осталось, результат 0
  2. Если есть только один результат среза, то этот срез
  3. Если есть хотя бы два среза, то результат:

(используя синтаксис Python)

max(slices[0] + sum(slices[1:]) - pizzaAmount(slices[1:]),
    slices[-1] + sum(slices[:-1]) - pizzaAmount(slices[:-1]))

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

Вы можете реализовать это с помощью DP (или запоминания), потому что массив действительно фиксирован, и вы можете просто рассматривать в качестве параметров первый и последний индекс слайса.

Чтобы решить исходную полную задачу, вам просто нужно попробовать все срезы в качестве начального среза и выбрать тот, который максимизирует результат.

6502
источник
Спасибо "6502". Я могу лучше визуализировать проблему, используя подсказку «рассматривая кусочки, только что помещенные в ряд, и выбирая их с одного из двух концов». Данное рекуррентное отношение также заботится об оптимальном выборе со стороны оппонента. Я скоро опубликую формальный алгоритм. Спасибо, парни!!
Просто любопытно, каков порядок сложности для этого алгоритма? 0 (n * 2 ^ n)?
@ Акрон: Это то, что было бы без подхода динамического программирования или запоминания. Однако вы можете воспользоваться тем фактом, что результат выполнения pizzaAmountзависит только от того, каковы индексы начала и конца оставшихся кусочков, а не от последовательности того, какие кусочки пиццы вы и ваш друг уже съели, чтобы вы могли сохранить результат в матрица, чтобы избежать пересчета. Порядок алгоритма поэтому O (n ** 2).
6502
Если кто-то все еще пытается понять, эта ссылка имеет очень хорошее объяснение.
Амит Шекхар
3

Для части пиццы определите F(i,j)как максимум, сколько человек может съесть первым кусочком. Кусочками части пиццы (i,j)являются:

if i <= j than slices i, i+1, ..., j-1, j
if i > j than slices i, i+1, ..., n-1, n, 1, 2, ..., j-1, j
and we don't define it for whole pizza, abs(i-j) < n-1

Определите R(i,j)(сколько осталось для второго человека) как sum(S_x, x in slices(i,j)) - F(i,j).

С:

F(i,i) = S_i,
F(i,j) = max( S_i + R(i+1,j), S_j + R(i,j-1) ),

Максимум, что может съесть Алиса, рассчитывается по формуле:

max( S_i + F(i+1, (i-1) if i > 1 else n) ).
ставка
источник