动态规划题讲解
【问题描述】
写一个程序,从标准输入上读入一个正整数N(1 <= N <=1000),计算出N元人民币兑换成1分、2分和5分的硬币,有多少种可能的组合。将结果以整数的方式输出到标准输出上,占一行。
【输入形式】
正整数N。(1 <= N <=1000)
【输出形式】
整数。
【输入样例】
1
【输出样例】
541
【时间限制】
1s
【空间限制】
65536KB
#include<stdio.h>
#define maxrow 3
#define maxcol 500000
int dp[maxrow][maxcol];
//dp[x][y]表示前x种硬币凑出y元的方案数
//有递推式
//k = [y / v[x]](向下取整)
//dp[x][y] = dp[x - 1][y - v[x] * 0] + dp[x - 1][y - v[x] * 1] + ... + dp[x - 1][y - v[x] * k]
//该公式可以理解为
//使用前x种硬币的方案数=(使用一个第x硬币前提下,使用前x-1种硬币解决掉剩余钱的方案数)+<pre name="code" class="cpp">//(使用两个第x硬币前提下,使用前x-1种硬币解决掉剩余钱的方案数)+..............+<pre name="code" class="cpp">//(使用[y/v[x]]个第x硬币前提下,使用前x-1种硬币解决掉剩余钱的方案数)
//而
//when y>=v[x]
//dp[x][y - v[x]] = dp[x - 1][y - v[x] * 1] + ... + dp[x - 1][y - v[x] * k]
//= > dp[x][y] = dp[x - 1][y] + dp[x][y - v[x]];
//when y = v[x]
//dp[x][y] = dp[x - 1][y]+1
//= >dp[x][0] = 1(for x in [0,x])
//这里为了能够清楚的讲解动态规划的状态转移,选择空间复杂度为O(maxRow*maxCol)的做法,实际上可以优化为O(maxCol)
int main(){
int money;
int i;
int j;
int k;
int v[3] = { 1, 2, 5 };
scanf("%d", &money);
money *= 100;
for (i = 0; i <= money; ++i){
dp[0][i] = 1;
}
for (i = 0; i < maxrow; ++i){
dp[i][0] = 1;
}
dp[1][1] = 1;
for (i = 1; i < maxrow;++i){
for (j = v[i]; j <= money; ++j){
if (j >= v[i]){
dp[i][j] = dp[i - 1][j] + dp[i][j - v[i]];
}
}
if (i < maxrow - 1){
for (k = 1; k < v[i]; ++k){
dp[i + 1][k] = dp[i][k];
}
}
}
printf("%d", dp[maxrow-1][money]);
system("pause");
return 0;
}