有关动态编程的作业。使我的代码更高效?

时间:2018-11-13 18:21:39

标签: algorithm dynamic pseudocode memoization

我有一个关于动态编程的作业。 我要设计一种执行以下操作的高效算法: 有一条小路,布满斑点。用户可以使用一系列按钮向前移动到路径的末端。有3个按钮。一项使您前进2个点,一项使您前进3个点,一项使您前进5个点。路径上的斑点是黑色或白色,并且您不能落在黑色斑点上。该算法找到到达终点所需的最少按钮按下次数(过去最后一个点,可能会过冲)。 用户输入的是“ n”个斑点的数量。并用n数量的B或W(黑色或白色)填充阵列。第一点必须是白色。到目前为止,这是我所拥有的(仅是伪造的):

int x = 0
int totalsteps = 0
n = user input
int countAtIndex[n-1] <- Set all values to -1 // I'll do the nitty gritty stuff like this after 
int spots[n-1] = user input

pressButton(totalSteps, x) {
    if(countAtIndex[x] != -1 AND totalsteps >= countAtIndex[x]) {
        FAILED } //Test to see if the value has already been modified (not -1 or not better)
    else
        if (spots[x] = "B") {
            countAtIndex[x] = -2 // Indicator of invalid spot
            FAILED }
        else if (x >= n-5) { // Reached within 5 of the end, press 5 so take a step and win
                GIVE VALUE OF TOTALSTEPS + 1 A SUCCESSFUL SHORTEST OUTPUT 
                FINISH }
        else
            countAtIndex[x] = totalsteps
            pressButton(totalsteps + 1, x+5) //take 5 steps
            pressButton(totalsteps + 1, x+3) //take 3 steps
            pressButton(totalsteps + 1, x+2) //take 2 steps
}

我很高兴看到这看起来很糟糕,但是我希望它能顺利通过,我只想确保理论是正确的,然后再写得更好。我想知道这是否不是解决此问题的最有效方法。除此之外,在有大写字母的地方,我不确定如何使程序“失败”或如何返回“成功”值。 任何帮助将不胜感激。

我应该添加一个不清楚的地方,我使用countAtIndex []来存储到达路径中该索引的移动次数。也就是说,位置3(countAtIndex [2])的值可能为1,这意味着它采取了1步才能到达该位置。

1 个答案:

答案 0 :(得分:2)

我正在将我的评论转换为答案,因为这对于评论来说太长了。

总有两种方法可以解决动态编程问题:通过备忘录自上而下或通过系统填充输出数组自下而上。我的直觉说,自下而上的方法的实现会更简单。我的回答是提供该方法的示例。我将把它留给读者作为练习来写形式算法,然后执行该算法。

因此,例如,假设输入数组的前11个元素是:

index:  0 1 2 3 4 5 6 7 8 9 10 ...
spot:   W B W B W W W B B W B  ...

为解决该问题,我们创建了一个输出数组(也称为DP表),以保存我们知道的有关该问题的信息。最初,除了第一个元素设置为0之外,输出数组中的所有值都设置为无穷大。因此,输出数组如下所示:

index:  0 1 2 3 4 5 6 7 8 9 10 ...
spot:   W B W B W W W B B W B
output: 0 - x - x x x - - x -

其中-是一个黑色空格(不允许),而x被用作无穷大的符号(无法到达或尚未到达的点)。

然后,我们从表的开头进行迭代,并不断更新条目。

从索引0开始,我们可以一举达到2和5。我们不能移到3,因为那个点是黑色的。因此,更新后的输出数组如下所示:

index:  0 1 2 3 4 5 6 7 8 9 10 ...
spot:   W B W B W W W B B W B
output: 0 - 1 - x 1 x - - x -

接下来,我们跳过索引1,因为该点是黑色的。因此,我们继续进行索引2。从2开始,我们可以达到4,5和7。索引4尚未达到,但是现在可以通过两个步骤实现。从2跳到5将在两个步骤中达到5。但是只要一步之遥就可以达到5,因此我们不会更改它(这是递归关系所在的位置)。我们不能移到7,因为它是黑色的。因此,在处理完索引2之后,输出数组将如下所示:

index:  0 1 2 3 4 5 6 7 8 9 10 ...
spot:   W B W B W W W B B W B
output: 0 - 1 - 2 1 x - - x -

跳过索引3(黑色)和处理索引4(可以达到6和9)之后,我们得到:

index:  0 1 2 3 4 5 6 7 8 9 10 ...
spot:   W B W B W W W B B W B
output: 0 - 1 - 2 1 3 - - 3 -

处理索引5不会有任何变化,因为7,8,10都是黑色的。索引6不会发生任何变化,因为8是黑色,已经可以通过三步到达9,并且我们没有显示索引11。因为索引7和8是黑色,所以它们被跳过。从9开始的所有跳转都进入了数组的未显示部分。

因此,如果目标是到达索引11,则移动次数将是4,而可能的路径将是2,4,6,11或2,4,9,11。或者,如果数组继续,我们将简单地遍历数组,然后检查数组的最后五个元素以查看移动最少的元素。