HDU-1284:钱币兑换问题 推理+动态规划(dp)
文章目录
题目大意: 题目链接 HDU 1284(点击可进入网页提交)
在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。
输入:
每行只有一个正整数N,N小于32768。
输出:
对应每个输入,输出兑换方法数。
思路:
方法1:
在看到题目后,我们可以很自然地(请原谅我用如此恶劣的词)想到暴力枚举,那么问题来了,该如何枚举呢?其实我们仔细想一下就可以发现对于每一种硬币的个数来说,它所出现次数一定是一个区间。
如何理解这句话呢?我们以3分的硬币的个数为例,它在所有的排列组合中,所出现的最少次数一定是0,即将钱n全部分成1分和2分的硬币,不包含3分硬币,这是一种合理的方案;好了,那么它最大次数,也可以很快算出为 n/3 (向下取整),既然最大为 n/3,那么小于等于n/3的个数也能出现,所以3分硬币所出现个数 cnt1 的区间为 0<=cnt1<=n/3。
分完了3分硬币,还剩下的钱为 n-3cnt,那么接下来我们考虑2分硬币,同样的思考方式,2分硬币的最小个数为0,最大个数为 (n-3cnt1)/2 ; 所以2分硬币出现个数cnt2的区间为 0<=cnt2<=(n-3*cnt1)/2。
3分硬币和2分硬币都分完了,剩下的都是1分硬币了,数量是可以确定的,所以不用考虑了。
所以我们可以用一层循环来枚举3分硬币的个数,然后用变量ans加上2分硬币的个数,循环完所得到的ans就是答案。
说了这么多,其实它的代码是非常简单的。
int ans=0;//用来记录答案for(int cnt1=0;cnt1<=n/3;cnt1++){ans+=(n-3*cnt1)/2+1; //即0到(n-3*cnt1)/2 的个数为 (n-3*cnt1)/2+1;}//得到的ans为答案
贴一发AC代码:
#include <iostream>#include <cstdio>using namespace std;int main(){ int n; while(cin>>n) { int ans=0;//用来记录答案 for(int cnt1=0;cnt1<=n/3;cnt1++) { ans+=(n-3*cnt1)/2+1;//即0到(n-3*cnt1)/2 的个数为 (n-3*cnt1)/2+1; } if(n==1) ans=1; if(n==2) ans=2; cout<<ans<<endl; } return 0;}
方法2:
动态规划(dp)
因为有三种硬币,所以我们可以刷新三次dp数组,变量i表示几分硬币,变量j表示钱;所以可以写出递推方程为 dp[j]+=dp[j-i];
AC代码如下:
#include <iostream>#include <cstdio>using namespace std;int dp[35000];void solve(){ dp[0]=1; for(int i=1;i<=3;i++) //三次刷新 { for(int j=i;j<32768;j++) { dp[j]+=dp[j-i]; } }}int main(){ int n; solve(); while(cin>>n) { cout<<dp[n]<<endl; } return 0;}
希望通过本篇博客你能有所收获!加油!