您的位置:首页 > 其它

完全背包之钱币兑换问题

2015-04-27 15:46 239 查看


钱币兑换问题

在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。

输入:每行只有一个正整数N,N小于32768。

输出:对应每个输入,输出兑换方法数。

Sample input:

2934

12553

Sample output:

718831

13137761

这道题目呢,有好多种解法,我专门查找了它的动态规划解法,结果竟然找不到带解释的

,搞了好久才搞出来。

刚开始的时候呢,觉得和以前做过的一道名叫超级台阶的题目很像,就用迭代的方法写了代码:

#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元时的种类数的表







代码:
#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;
}


这一题还得再想想。。。。。先写到这吧。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: