使用动态编程技术如何解决“披萨拣选问题”?


9

温克勒的披萨挑选问题:

  • 一片圆形比萨饼饼n,其中切片i有面积,S_i即每个饼片的面积都不同。
  • 食者爱丽丝(Alice)和鲍勃(Bob)轮流采摘切片,但在馅饼中留出多个空隙是不礼貌的(考虑到不允许这样做)。
    • 因此,每个食者被限制采取与开放区域相邻的两个切片之一。爱丽丝先行,两个食客都在寻找尽可能多的馅饼。

如果Alice和Bob都能完美地发挥其比萨饼的消费量,那么动态编程算法将如何确定Alice吃多少馅饼?

我的理解:

在一般的DP问题中,我们继续寻找可以使用递归树或更紧密地使用DAG可视化的子问题。在这里,我没有找到任何线索可以找到这里的子问题。

在这里,对于给定的S_i集合,我们需要最大化Alice所吃的切片的面积。这将取决于从(n-1)个排列中选择一个披萨片的排列。在每n \ 2圈内,Alice会从两个可用选项中选择一个最大面积切片,这将为我们提供置换的切片总​​面积。我们需要找到所有此类排列的切片区域。然后从这些中最大化。

有人可以帮助我前进吗?

Answers:


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”。我可以利用“考虑刚刚放在一行上的切片并从两端之一中进行拾取”的提示来更好地形象化该问题。给定的递归关系也在照顾对手的最佳选择。我将尽快发布正式算法。谢谢你们!!

很好奇,此算法的复杂度是多少?0(n * 2 ^ n)?

@Akron:这就是没有动态编程方法或备注的情况。但是,您可以利用以下事实:do的结果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) ).
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.