c++ - 爬楼梯 DP 问题基本案例概念

标签 c++ dynamic-programming

问题: 你正在爬楼梯。需要n步才能到达顶部。 每次您可以跳 1 步、2 步或 3 步。您总共可以通过多少种方式跳到顶部?

我的解释: 好吧,我正在考虑应用递归,因为我可以通过解决类似的子问题来找到解决方案,并且在这个过程中,会有很多重叠的子问题,所以我将数组数据结构来保存类似子问题的名称,这样我就不需要解决同一子问题两次。所以我使用自上而下的 DP 方法。

我的疑问:

现在要构建解决方案,我需要一个基本情况,其中程序流程结束并返回到其父节点(如果将其可视化为树)。所以我所想的基本情况就像我在地板上、在地面 0 时一样,所以我没有其他方法可以达到地面 0 状态,所以这是基本情况。

n=0时,我应该返回0或1,这是我的疑问?好吧,我已经编写了代码,因此当我返回 1 而不是 n=0 时的 0 时,代码就会工作。那么为什么当n=0时我应该返回1,背后的原因是什么?请帮忙!!!

我的代码:

#include <iostream>
using namespace std;

int climbing_ladders_topDown(int n, int k, int dp[]){
    //Base Case
    if(n==0){
        return 1;
    }

    //LookUp
    if(dp[n]!=0){
        return dp[n];
    }

    //Recursive Case
    int total_num_of_ways = 0;
    for(int jumps=1;jumps<=k;jumps++){
        if(n-jumps>=0){
            total_num_of_ways += climbing_ladders_topDown(n-jumps,k,dp);
        }
    }
    
    dp[n] = total_num_of_ways;
    return dp[n];
}

int main() {
    int num_of_stairs = 4;
    int num_of_jumbs = 3;
    int dp_arr[100] = {0};

    cout<<climbing_ladders_topDown(num_of_stairs,num_of_jumbs,dp_arr);
    
    return 0;
}

输出:7

正确的代码流程(感谢@appleapple):

#include <iostream>
using namespace std;

int climbing_ladders_topDown(int n, int k, int dp[]){

    //Base Case
    if(n==0){
        return 0;
    }

    //LookUp
    if(dp[n]!=0){
        return dp[n];
    }

    //Recursive Case
    int total_num_of_ways = 0;

    for(int jumps=1;jumps<=k;jumps++){
        
        if(n-jumps > 0){
            total_num_of_ways += climbing_ladders_topDown(n-jumps,k,dp);
        }
        
        if(n-jumps == 0){ // have reach the end or ground 0, base so no more move possible in downward direction
            total_num_of_ways += 1; 
        }
        
        if(n-jumps < 0){ //we can't move to -ve state/underground, because it doesn't exist
            total_num_of_ways += 0;
        }

    }
    
    dp[n] = total_num_of_ways;
    
    return dp[n];
}

int main() {

    int num_of_stairs = 4;
    int num_of_jumbs = 3;
    
    int dp_arr[100] = {0};

    cout<<climbing_ladders_topDown(num_of_stairs,num_of_jumbs,dp_arr);
    
    return 0;
}

最佳答案

因为您在这里要求它为1 (f(0) = 1)

for(int jumps=1;jumps<=k;jumps++){
   if(n-jumps>=0){
      total_num_of_ways += climbing_ladders_topDown(n-jumps,k,dp); // here
   }
}

如果你想要f(0)=0,因为递归到f(0)不再有意义了(没有可能的解决方案,就像f(-1))

这种情况的算法将变为

if(n<=0){ // not really necessary as implied inside the loop
   return 0; // not possible
}
///...
int total_num_of_ways = 0;
for(int jumps=1;jumps<=k;jumps++){
   if(n-jumps>0){
      total_num_of_ways += climbing_ladders_topDown(n-jumps,k,dp);
   }
   if(n-jumps==0){ // have reach the end, no more move possible
      ++total_num_of_ways; // you put this under n=0
   }
   // if(n-jumps<0){/*do nothing*/}
}

注意:f(0) = 0f(0) = 1 提供了一些不同的含义。 (所以算法也改变了)

  • f(0) = 1 表示不移动是一种可能的解决方案。
  • f(0) = 0 表示至少需要移动 1 步
  • 两者都意味着一旦离开0(无负向移动)就不可能返回,顺便说一句。

关于c++ - 爬楼梯 DP 问题基本案例概念,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69742205/

相关文章:

c++ - 当基类函数已经因不同的访问而重载时如何处理名称隐藏

c++ - 在 boost.python 中包装 std::vector<pointer*>

c# - 调用 C++/CLI 包装器时出现外部异常 E0434352

c++ - 我的带内存的动态编程算法有什么问题?

algorithm - 如何找到最大和的递增数字子序列?

c++ - 在 CMake/C++ 项目中高效地使用 SublimeText 和 SublimeClang

c++ - 如何在 C++ 中 epur std::string?

c - 集合动态规划

c++ - 如何使用动态编程自顶向下方法解决这个问题?

algorithm - 覆盖目标的传感器的最小成本子集