动态编程-跳千斤顶

时间:2018-12-09 14:04:15

标签: algorithm dynamic-programming

使用DP技术可以解决以下问题吗?

不需要代码。想法应该足够。

Marvel提出了一个名为Jumping Jack的新超级英雄。这个超级英雄的共同创造者是一位数学家,他为角色的力量增添了数学色彩。

因此,Jumping Jack最杰出的力量之一就是跳跃距离。但是,这个超级大国有一定的限制。

跳跃杰克只能跳跃—

  1. 到比当前距离小一公里的数字。例如,如果他距离目的地12公里,那么他将无法直接跳到目的地,因为他只能跳到11公里之外的位置。
  2. 到当前距离的一半。例如,如果Jumping Jack距目的地12公里,那么他将无法直接跳至目的地,因为他只能跳至6公里的位置。
  3. 达到当前距离的距离。例如,如果Jumping Jack再离目的地12公里,那么他将无法直接跳到目的地,因为他只能跳到4公里之外的位置。

因此,您需要帮助超级英雄开发一种算法,以最少的步骤到达目的地。目的地被定义为距离变为1的地方。跳跃的杰克应该跑完最后1公里!而且,他只能跳到离主要目的地整数倍距离的目的地。例如,如果他在10公里处,则跳过距离的1/3,就不能达到距离的10/3。他必须跳到5或9。

因此,您必须找到到达目的地所需的最小跳数。例如,如果目的地在10公里之外,则有两种方法可以到达目的地: 10-> 5-> 4-> 2-> 1(四跳) 10-> 9-> 3-> 1(三跳) 这些中的最小值是3,因此超级英雄至少需要跳跃3次才能到达该点。

3 个答案:

答案 0 :(得分:0)

在解决所有动态编程问题时,请牢记以下两点:

  • 最佳子结构(查找最小跳转次数)
  • 子问题重叠(如果再次遇到相同的子问题,请不要解决它,而要使用已经计算出的结果-是的,您必须将子问题的计算结果存储为将来参考)

始终尝试为手头的问题提供递归解决方案(现在不要直接着手研究递归解决方案,而是先自己尝试一下):

df_1[, paste0("Period_", windows) := frollmean(Dist, windows)]

现在您知道我们已经设计了一个递归解决方案。下一步是将解决方案存储在一个数组中,以便将来可以使用它并避免重新计算。您可以简单地获取一维整数数组并继续存储它。

请记住,如果您采用自上而下的方法-称为记忆,而如果采用自下而上的方法-则称为动态编程。看看this,看看这两种方法之间的确切区别。

一旦您有了递归解决方案,现在就可以考虑构造一个自底向上的解决方案或自顶向下的解决方案。

在自下而上的解决方案策略中-您首先填写基本案例(calCulateMinJumps(int currentDistance) { if(currentDistance == 1) { // return jumps - you don't need to recurse here } else { // find at what all places you can jump jumps1 = calculateMinJumps(n-1) + 1 if(currentDistance % 2 == 0) jumps2 = calculateMinJumps(n/2) + 1 if(currentDistance % 3 == 0) jumps3 = calculateMinJumps(n/3) + 1 return minimum(jumps1, jumps2, jumps3) // takes jump2 and jump3 only if they are valid } } ),然后在其基础上进行构建以达到最终所需的解决方案。

现在,我没有给您完整的策略,因为这将是您要执行的任务。您确实会找到解决方案。 :)-根据您的请求-Jumping Jack should cover the last 1 km running!

答案 1 :(得分:0)

首先,请考虑一下这个硬币兑换问题,可能会帮助您了解自己的硬币问题,两者基本相同: Coin change - DP

其次,通常,如果您知道自己的问题有DP解决方案,则可以执行4个步骤来解决它。当然,您可以省略前三个步骤中的一个或全部。

  1. 找到回溯解决方案。(在此省略)
  2. 根据回溯解决方案查找问题的递归公式。 (稍后描述)

  3. 根据递归公式编写递归代码。(略)

  4. 根据第3步编写一个迭代代码。(省略)

最后,对于您的问题,该公式并不难找出:

minStepFor(distance_N)=Math.min(minStepFor(distance_N-1)+1),
                                minStepFor(distance_N/2)+1, 
                                minStepFor(distance_N/3)+1)

想象一下杰克正站在距离N点处,而他第一次走最多有三个选择:转到N-1点,N/2点或N/3点(如果N/2N/3不是整数,则他的选择将减少。)

对于他的每一个选择,最小步幅均为minStepFor(left distance)+1,因为他已经进行了1步移动,并且肯定地,他将尝试在其左移步幅中进行最小步幅。每个选择的left distancedistance_N-1distance_N/2distance_N/3

这就是理解公式的方式。有了它,不难编写一个递归解决方案。

答案 2 :(得分:0)

考虑f [1] = 0,因为JumpingJack离1公里远时所需的跳数没有。 使用该基值以以下方式解决F [2] ... f [n]

        for(int i=2; i<=n; i++) {
            if(i%2==0 && i%3==0) {
                f[i] = Math.min(Math.min(f[i-1]+1, f[i/2]+1), f[i/3] + 1);
            }
            if(i%2==0) {
                f[i] = Math.min(f[i-1]+1, f[i/2]+1);
            }else if(i%3==0) {
                f[i] = Math.min(f[i-1]+1, f[i/3] + 1);
            }else{
                f[i] = f[i-1]+1;
            }
        }
        return f[n];

您无需多次递归地解决子问题!