达到游戏结束的最低步数

时间:2014-04-04 15:43:56

标签: algorithm dynamic-programming mathematical-optimization

我正在编写一个非常简单的游戏。

  • 给出n个砖块,其中k个颜色放在一个圆圈中
  • 如果砖块被移除,与其相邻且具有相同颜色的砖块将被移除。
  • 对于每个步骤,玩家只能移除一块砖(但如果相邻的砖块存在并且颜色相同,则步骤将不计算在内)
  • 游戏结束iff所有砖块已被移除

如何获得到达游戏结束所需的最低步数? (我目前的解决方案是回溯,我正在考虑动态编程)

实施例

4 bricks with 3 colors R, G, B place like this:
R G B B G R B G B R R G (R) (let number it 0, 1, 2, ...)

Remove 2 -> 3 will be removed (step = 0)
R G <B> <B> G R B G B R R G

Remove 0 (step = 1)
<R> G * * G R B G B R R G

Remove 4 -> 1, 11 will be removed (step = 1)
* <G> * * <G> R B G B R R <G>

Remove 10 -> 9, 5 will be removed (step = 1)
* * * * * <R> B G B <R> <R> *

Remove 7 (step = 2)
* * * * * * B <G> B * * *

Remove 8 -> 6 removed -> end game, step = 2, minimal
* * * * * * <B> * <B> * * *

真的很抱歉我的英文

1 个答案:

答案 0 :(得分:0)

O(N 3 )复杂度的解决方案在哪里。

动态编程。要了解它是如何工作的,并考虑它,请考虑删除所有块的一些序列。现在让我们标记所有后续块,一步一步删除。我们将在初始圈子上标记它们。每个步骤都可以标记为相同颜色的块段(之前删除了所有不同的块)。以下是您的示例的图片:

initial: RGBBGRBGBRRG
step 1:    BB
step 2:  R
step 3:  -G--G      G
step 4:  -----R   RR-
step 5:  ------B B---
step 6:         G

每个&#39;&#39;要么不相交,要么早先完全在后面。因此,有一种方法可以在某个时刻打破圆圈。在你的例子中,它可以在块5和6之间完成(或者也可以在6和7之间)。

现在你可以看到解决方案的结构 - 我们必须知道完全删除一些连续段块的最小步骤数,而不是块的圆。为此,我们将有一个动态编程F(i,j) =&#34;最小数量的步骤,从i到j&#34;完全删除块。请注意,可能存在j < i,这意味着段在初始块中越过边缘(如上图中的步骤5)。如果我们可以计算F,则所有F(i, (i+n-1)%n) for i=0..n-1的答案都将最小。

基数非常明显,空段(j == i-1)需要0步,一个块段(i == j)需要1步。

其余的更难。考虑段中的第一个块。 这是某些步骤中删除的某些块的开始。它必须在相同颜色的块处结束。因此,我们有:

F(i,j) = min{G(i,t)+F(t+1,j) },  i<=t <= j, blocks t and i have the same color

这里,G(i,j)是另一个动态编程,给出答案&#34;从i到j去除所有块需要多少步骤,在最后一步删除块i和j&#34; 。请记住,块在这里,而不是在这里。

我们尝试t作为细分的结尾,因此我们需要G(i,t)步骤来删除所有这些块。我们需要另外F(t+1,j)步骤来删除所有其他块。

GF具有相同的基数。现在回顾上面的图片。段中的最后一步可以不仅包括两个块i和j(如步骤3)。它可能有一些中间块。我们将尝试所有可能的中间块:

G(i,j) = min{F(i+1, t-1)+G(t, j)}, i < t <= j, blocks t and i have the same color.

这里发生了什么?我们认为块t是最后删除块的下一行。为此,我们首先必须完全删除it之间的所有块。它需要F(i+1, t-1)个步骤。然后,我们将计算从tj删除所有块所需的步骤,最后删除角块。它需要G(t, j)个步骤。现在可以免费删除块i,因为它与块t相邻,并且可以在最后一步与其一起删除。请注意,t如何等于j。因此,我们可以仅使用两个移除的块来覆盖移动。

该解决方案需要O(N 2 )存储器和O(N 3 )时间。 实现它的最简单方法是延迟动态编程(使用递归函数并记忆答案)。

如果您还需要一系列步骤,那就更难了。每个函数F和G还应该存储中间变量t值,这给出了最小答案。然后,您可以使用另一个递归函数重建步骤,该函数将仅使用“t&#39;”的存储值来镜像F和G计算。通过这种方式,您将获得所有段,现在您可以将它们从最小到最大输出。

编辑:

注意,因为j可能小于iF内的G,所以您应该小心。问题i <= t <= j不是t ij开始增加直到达到i < t <= j(它可能会在结束时运行并从n-1变为0) 。 j==i-1的相似内容。

此外,无法为函数传递空段,因此F不应该有基础。相反,如果没有要移除的阻止,则不应调用G和{{1}}。