完全背包之钱币兑换问题
2015-04-27 15:46
239 查看
钱币兑换问题
在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。输入:每行只有一个正整数N,N小于32768。
输出:对应每个输入,输出兑换方法数。
Sample input:
2934
12553
Sample output:
718831
13137761
这道题目呢,有好多种解法,我专门查找了它的动态规划解法,结果竟然找不到带解释的
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/cry.gif)
,搞了好久才搞出来。
刚开始的时候呢,觉得和以前做过的一道名叫超级台阶的题目很像,就用迭代的方法写了代码:
#include<iostream> using namespace std; int main() { int n; while(cin>>n) { long long a[10000]; a[0]=0; a[1]=1; a[2]=2; a[3]=3; for(int i = 4;i <= n;i++) a[i]=a[i-1]+a[i-2]+a[i-3]; cout<<a <<endl; } return 0; }
检查的时候发现数据错了,到底错哪里呢?结果发现虽然台阶那道题虽然同样的步幅同样可以重复多次,和这里的同一个硬币可以使用多次很类似,但是在同样数值的数字台阶里的数目和钱币的组合数目确实不同的。举个例子:假设我有五个台阶,其中有一种走法是一次性走2步,再走2步,在走一步。和另外一种走法先走一步,再走两次两步是不相同的两种方法。但是如果有5元钱,2,2,1的组合方法和1,2,2的组合方法却是相同的。也就是说,前者可以看成是排列,而后者是组合。所以最后用超级台阶所算出来的数目要远远大于正确的数目。所以这种想法是行不通的。
后来就有了下面的想法:
假设我们有5元要兑换:
就会有:
---------------------------------------------
1+1+1+1+1=5 钱币的最大面值为1元的时候
---------------------------------------------
2+2+1 钱币的最大面值为2元的时候
2+1+1+1
---------------------------------------------
3+2 钱币的最大面值为3元的时候
3+1+1
---------------------------------------------
聪明的你一定发现了,组合成五元的种类数也就是三者方法数之和。
然后就是用数组来表示:
其中dp[i[j]表示所能用(且必须用)的钱币是i要组合成j元的最多组合数。那么状态转移方程就是
dp[i][j]=dp[1][j-1]+dp[2][j-2]+dp[3][j-3];
列表:这是钱币总共是11元时的种类数的表
![](file:///D:\Document_x64\Documents\Tencent Files\1247846793\Image\C2C\K8QW8MLX2}YRH%IL58%0FC4.png)
![](file:///D:\Document_x64\Documents\Tencent Files\1247846793\Image\C2C\K8QW8MLX2}YRH%IL58%0FC4.png)
代码:
#include<iostream> #include<cstring> using namespace std; int main() { int n; while(cin>>n) { int dp[100][100]; memset(dp,0,sizeof(dp)); dp[2][0] = 1 ; dp[3][0] = 1 ; for(int j = 0 ; j <= n ; j++) dp[1][j] = 1 ; for(int j =2;j<=3;j++){ for(int i =1;i <=n;i++){ if(i<j) dp[j][i]=dp[j-1][i]; else for(int k=1;k<=i&&k<=j;k++){ dp[j][i]+=dp[k][i-k]; } } } for(int i =1;i<=3;i++){ for(int j = 0;j<=n;j++){ cout<<dp[i][j]<<" "; } cout<<endl; } } return 0; }
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
然后开始优化数组。我们可以发现,要求某一个元素的值,总是会用到在列上面位于它前面的值(我不是很擅长优化,只是这样想的)。然后优化后的代码就是这样。
#include<iostream> #include<cstring> using namespace std; int dp[1000000]; main() { int n; while(cin>>n) { memset(dp,0,sizeof(dp)); dp[0] = 1; for(int i = 1;i <= 3; i++){ for(int j = i; j <= n;j++){ dp[j] += dp[j-i]; } } cout<<dp <<endl; } return 0; }
这一题还得再想想。。。。。先写到这吧。
相关文章推荐
- HDU1284:钱币兑换问题(完全背包)
- HDU 1284 钱币兑换问题 母函数 or 完全背包
- 钱币兑换问题(完全背包)
- HDU 1284 钱币兑换问题(母函数,完全背包)
- HDU 1284 钱币兑换问题 动态规划完全背包
- hdu 1284 钱币兑换问题( 完全背包)
- HDU 1284 钱币兑换问题(完全背包:入门题)
- hdu 1284 钱币兑换问题(完全背包)
- HDU 1284 钱币兑换问题 (完全背包)
- 【完全背包】钱币兑换问题
- 【完全背包/母函数】HDU1284钱币兑换问题
- HDOJ(HDU).1284 钱币兑换问题 (DP 完全背包)
- 【背包专题】H - 钱币兑换问题 hdu1284【完全背包】
- HDU 1284(钱币兑换问题)完全背包求方案总数
- hdu 1284 钱币兑换问题 完全背包基础题
- HDU 1284 钱币兑换问题(完全背包)
- hdu 1284 钱币兑换问题(完全背包)
- 钱币兑换问题---hdu1284(完全背包)
- hdu 1284 钱币兑换问题(完全背包 母函数)
- hdu 1284 钱币兑换【完全背包问题】