Algorithm 硬币兑换算法和伪代码:需要澄清吗

Algorithm 硬币兑换算法和伪代码:需要澄清吗,algorithm,dynamic-programming,coin-change,Algorithm,Dynamic Programming,Coin Change,我试图理解硬币兑换问题的解决方案,但遇到了一些困难 在,动态规划解决方案有一个伪代码解决方案,如下所示: n = goal number S = [S1, S2, S3 ... Sm] function sequence(n, m) //initialize base cases for i = 0 to n for j = 0 to m table[i][j] = table[i-S[j]][j] + table[i][j-1] 这是一个非常标准的O(

我试图理解硬币兑换问题的解决方案,但遇到了一些困难

在,动态规划解决方案有一个伪代码解决方案,如下所示:

n = goal number
S = [S1, S2, S3 ... Sm]

function sequence(n, m)
   //initialize base cases

   for i = 0 to n
     for j = 0 to m
       table[i][j] = table[i-S[j]][j] + table[i][j-1]
这是一个非常标准的
O(n^2)
算法,它避免了使用二维数组多次重新计算相同的答案

我的问题有两个方面:

  • 如何定义基本情况并将其作为初始值合并到
    表[]【】
  • 如何从表中提取不同的序列
  • 关于问题1,该算法有三种基本情况:

    • 如果n==0,则返回1
    • 如果n<0,则返回0

    • 如果n>=1&&m我们可以用至少两种不同的方法实现动态规划算法。一种是使用记忆的自顶向下方法,另一种是自底向上迭代方法

      对于动态规划的初学者,我总是建议首先使用自上而下的方法,因为这将帮助他们理解动态规划中的循环关系

      因此,为了解决硬币兑换问题,您已经了解了循环关系的含义:

      table[i][j] = table[i-S[j]][j] + table[i][j-1]
      
      这种递推关系很好,但由于没有任何边界条件,因此定义得不太明确。因此,我们需要定义边界条件,以确保递归关系能够在不进入无限循环的情况下成功终止

      那么,当我们尝试沿着递归树往下走时会发生什么呢

      如果我们需要计算
      表[i][j]
      ,这意味着使用
      0
      类型的硬币将
      i
      更改为
      j
      类型的方法的数量,我们需要处理以下几种情况:

      1) 如果
      j==0怎么办

      如果
      j==0
      我们将尝试解决子问题
      表(i,j-1)
      ,该子问题不是有效的子问题。因此,一个边界条件是:

      if(j==0) {
        if(i==0) table[i][j] = 1;
        else table[i][j] = 0;
      }
      
      2) 如果
      i-S[j]<0

      我们还需要处理这个边界情况,我们知道在这种情况下,我们不应该试图解决这个子问题,也不应该为所有这些情况初始化
      表(i-S[j],j)=0

      总之,如果我们要从自上而下的记忆方法实现这种动态编程,我们可以这样做:

      int f(int i, int j) {
        if(calc[i][j]) return table[i][j];
        calc[i][j] = true;
        if(j==0) {
          if(i==0) return table[i][j]=1;
          else return table[i][j]=0;
        }
        if(i>=S[j])
          return table[i][j]=table[i-S[j][j]+table[i][j-1];
        else
          return table[i][j]=table[i][j-1];
      }
      
      实际上,我们也可以使用
      数组的值来帮助跟踪此子问题之前是否已计算过(例如,我们可以初始化值-1表示此子问题尚未计算)


      希望答案是清楚的。:)

      谢谢你的澄清。两点:
      calc
      的确切来源是什么?作为布尔条件,它在哪里设置为false?其次,作为一个二维数组,我将如何提取可能的序列?@Jason:
      calc
      是一个布尔型矩阵,它表示这个“子问题”以前是否计算过,如果计算过,那么我们不需要重新计算,我们只需使用以前的计算结果。这是dynamic的核心programming@Jason:尽管提取可能的序列是一个完全不同的问题,因为可能性的数量可能相当大,但您仍然可以使用向量v[i][j]来跟踪这一点,遵循类似的关系。