【问题标题】:Coin Change Bottom Up Dynamic Programming硬币变化自下而上的动态规划
【发布时间】:2013-04-16 14:59:12
【问题描述】:

http://uva.onlinejudge.org/external/6/674.html我正在努力解决这个问题。但请注意,这不是最小硬币找零问题,它要求我使用 50、25、15、10、5 和 1 美分硬币制作 N 美分的不同数量的方法。这很简单,所以我做了这个函数:

int count(int n, int m) // n is the N of the problem, m is the number of coin types and s[] is {1, 5, 10, 25, 50}
{
  if (n == 0)
  {
    return 1;
  }

  if (n < 0)
  {
    return 0;
  }

  if (m < 0 && n >= 1)
  {
    return 0;
  }

  return DP[n][m - 1] + DP[n - s[m]][m];
}

添加带有记忆的动态编程也相当简单:

int count(int n, int m)
{
  if (n == 0)
  {
    return 1;
  }

  if (n < 0)
  {
    return 0;
  }

  if (m < 0 && n >= 1)
  {
    return 0;
  }

  if (DP[n][m - 1] == -1 || DP[n - s[m]][m] == -1)
  {
    return count(n, m - 1) + count(n - s[m], m);
  }
  else
  {
    return DP[n][m - 1] + DP[n - s[m]][m];
  }
}

然而,这些都不够快 - 我需要自下而上的动态编程,但我在编写它时遇到了困难,即使得到了 Algorithmist - http://www.algorithmist.com/index.php/Coin_Change 的帮助。

void generate()
{
  for (i = 0; i < MAX; i++)
  {
    for (u = 0; u < m; u++)
    {
      if (i == 0)
      {
        DP[i][u] = 1;
      }
      else if (u == 0)
      {
        DP[i][u] = 0;
      }
      else if (s[u] > i)
      {
        DP[i][u] = DP[i][u - 1];
      }
      else
      {
        DP[i][u] = DP[i][u - 1] + DP[i - s[u]][u];
      }
    }
  }
}

由于某种原因,每个结果我都得到 0,这是我的完整代码:

#include <stdio.h>
#include <string.h>

using namespace std;

#define MAX 7490

int s[] = {1, 5, 10, 25, 50}, m = 5, input, DP[MAX][5], i, u;

int count(int n, int m)
{
  if (n == 0)
  {
    return 1;
  }

  if (n < 0)
  {
    return 0;
  }

  if (m < 0 && n >= 1)
  {
    return 0;
  }

  if (DP[n][m - 1] == -1 || DP[n - s[m]][m] == -1)
  {
    return count(n, m - 1) + count(n - s[m], m);
  }
  else
  {
    return DP[n][m - 1] + DP[n - s[m]][m];
  }
}

void generate()
{
  for (i = 0; i < MAX; i++)
  {
    for (u = 0; u < m; u++)
    {
      if (i == 0)
      {
        DP[i][u] = 1;
      }
      else if (u == 0)
      {
        DP[i][u] = 0;
      }
      else if (s[u] > i)
      {
        DP[i][u] = DP[i][u - 1];
      }
      else
      {
        DP[i][u] = DP[i][u - 1] + DP[i - s[u]][u];
      }
    }
  }
}

int main()
{
  memset(DP, -1, sizeof DP);
  generate();

  while (scanf("%d", &input) != EOF)
  {
    //printf("%d\n", count(input, 4));
    printf("%d\n", DP[input][4]);
  }

  return 0;
}

【问题讨论】:

  • 不要在链接后面隐藏相关信息。您链接到的页面将消失,对于遇到类似问题的任何人来说,该问题将变得毫无用处。
  • 也许这个答案有帮助(仅限算法):stackoverflow.com/a/2633921/104774

标签: c++ algorithm dynamic-programming coin-change bottom-up


【解决方案1】:

你在这里犯了错误:

else if (u == 0)
{
   DP[i][u] = 0;
}

它应该是DP[i][u]=1,因为您可以使用 1 美分硬币以 1 种可能的方式产生任何价值 i。即要拿 5 美分,您将拿 5 个 1 美分硬币,这是一种总共赚 5 美分的方法。

-----

顺便说一句,在您使用 count 方法的第一种方法中,您是否有这个:

if (DP[n][m - 1] == -1 || DP[n - s[m]][m] == -1)
{
  return count(n, m - 1) + count(n - s[m], m);
}

或者这个:

if (DP[n][m - 1] == -1 || DP[n - s[m]][m] == -1)
{
    return DP[n][m] = count(n, m - 1) + count(n - s[m], m);
}

如果你没有记住已经计算的结果,那么这个记忆检查if (DP[n][m - 1] == -1 || DP[n - s[m]][m] == -1) 将永远无法工作,这可能是你的第一种方法太慢的原因:-?

【讨论】:

  • 它成功了,非常感谢你的修复以及关于贪婪和记忆算法的提示。
猜你喜欢
  • 2023-03-20
  • 2019-07-26
  • 2018-02-25
  • 2012-11-24
  • 2011-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多