【问题标题】:How do I solve the Coin Row problem using dynamic programming?如何使用动态规划解决硬币排问题?
【发布时间】:2020-09-04 17:56:02
【问题描述】:

硬币排问题:有一排 n 个硬币,其值为正整数 C0, C2, . . . , Cn-1, 不一定不同。目标是在初始行中没有两个相邻的硬币不能被拾取的约束下,拾取最大数量的钱。

在下面的代码中,n 是我的数组 C 的大小(或硬币数量),此代码返回值 [10, 2, 4, 6, 3, 9, 5] 的正确结果(正确的结果是 25)。但是当我为值 [3, 12, 10] 或 [3, 12, 10, 2] 运行相同的代码时,我得到了错误的结果。 (对于一组值,结果应分别为 13 和 14)。

请帮我修复我的代码。

int max(int a, int b) {
  if(a > b) return a;
  return b;
}

int coin_row(int[] C, int n) {
  if(n==1) return C[0];
  if(n==2) return max(C[0],C[1];

  int F[n], i;
  F[0] = 0; F[1] = C[0];

  for(i = 2;i < n;i++) {
    F[i] = max(C[i] + F[i-2], F[i-1]);
  }

  return F[n-1];
}

【问题讨论】:

  • F 代表什么?如果F[i] 是您只能使用第一个i+1 硬币获得的最大金额,则应将F[0] = 0; F[1] = C[0]; 替换为F[0] = C[0]; F[1] = max(C[0], C[1]);,就像n 为1 或2 时一样。

标签: c algorithm dynamic-programming


【解决方案1】:

所有数字都是正数的声明使事情变得容易一些。从这些信息中,我们可以确定我们永远不想跳过两个连续的数字。我们只需要使用第一个数字计算可能的最佳序列,并将其与使用第二个数字可能的最佳序列进行比较。这是递归的理想选择。

int coin_row(int *C, int n) 
{
    int first_total;
    int second_total;

    if (n == 0) return 0;
    if (n == 1) return *C;
    if (n == 2) return max(*C, *(C+1));

    first_total = *C + coin_row(C+2, n-2);
    second_total = *(C+1) + coin_row(C+3, n-3);
    return(max(first_total, second_total));
}

通过将问题分解为一系列对,我们将列表视为一棵大型二叉树。在每一对中,您都可以选择第一个或第二个数字。计算每个子树的总数并返回最大值。例如,对于 {10, 2, 4, 6, 3, 9, 5},您的路径是:

          10                    2
          /\                   /\
         4  6                 6  3
        /\  /\               /\  /\
       3  9 9 5             9  5 5 -

【讨论】:

  • 用 200 个硬币的数组试试你的算法。会有性能问题。 OP 的“动态编程”标签暗示了原因。
  • 有趣,我没有意识到动态编程有特定的含义。感谢您指出了这一点。明天有机会我会更新我的答案。
  • 在以 10 开头的树中,您可以在最左边的分支上再添加一个数字,即 5。
【解决方案2】:

您的算法是正确的,但在实现中存在一些错误。 当您的循环从 i=2 开始时,您将跳过 C[1] 处的值。 由于您在 F 数组中包含 0 个硬币盒,因此 F[n] 的大小必须为 n+1 才能存在。通过上述更正,我们得出:

int max(int a, int b) {
  if(a > b) return a;
  return b;
}

int coin_row(int* C, int n) {
  if(n==1) return C[0];
  if(n==2) return max(C[0],C[1]);

  int F[n+1], i;
  F[0] = 0; F[1] = C[0];

  for(i = 2 ; i <= n + 1 ; i++) {
    F[i] = max(C[i-1] + F[i-2], F[i-1]);
  }
  return F[n];
}

【讨论】:

    猜你喜欢
    • 2016-10-25
    • 2015-05-08
    • 2020-09-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多