HDU 1284 钱币兑换问题
Problem Description
在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。
Input
每行只有一个正整数N,N小于32768。
Output
对应每个输入,输出兑换方法数。
Sample Input
2934
12553
Sample Output
718831
13137761
解题报告
此题首先排除暴力求解,根据题设条件,时间明显不足。第一眼看过去明显完全背包问题,之后思考可以通过数学方法解决。
方法一 数学方法
按照暴力求解方法,应该对A,B,C(分别面额为3,2,1)的硬币数量进行遍历。此时我们首先可以确定,面额为1的硬币完全不需要进行遍历,确定A,B数量后,总面额总不足的部分由C补充,因此只需要确定A,B数量。当确定A的数量,只需填入B,不足的部分由C来补充。因此当A数量确定后,只需查看B的装填方式有多少种。B的装填方式=(总面额-A*3)/2。
再对A进行遍历,即可的出装填数量。
#include<stdio.h>
int main()
{
unsigned int n,i;
long count;
while(scanf("%d",&n)!=EOF)
{
count=0;
for(i=0;i<=n/3;i++)
{
count+=(n-i*3)/2+1;
}
printf("%d
",count);
}
return 0;
}
方法二 动态规划
在网上看了很多把这个问题归于背包问题,仔细思考过后,觉得归于背包问题是在不妥当。不难找出该题的动态方程为F[N]=F[N-1]+F[N-2]+F[N-3](动态规划问题核心就是找出动态方程),只考虑N的三种硬币组合方式,N-1情况下放置一枚价值为一的硬币可以组成价值N,同理可得N-2,N-3,故得此动态方程。
#include<stdio.h>
int main()
{
int n,i,j;
int ar[35000]; //存储范围内值的组合方式,目测测试数据有问题,范围太小错误
ar[0]=1;
for(i=1;i<=3;i++) //动态方程组的转化
{
for(j=i;j<35000;j++)
{
ar[j]+=ar[j-i];
}
}
while(scanf("%d",&n)!=EOF)
{
printf("%d
",ar[n]);
}
return 0;
}
方法三 完全背包
网上很多关于方法二和方法三分类不清楚。
对于一个给定了背包容量、物品费用、物品间相互关系(分组、依赖等)的背包问题,除了再给定每个物品的价值后求可得到的最大价值外,还可以得到装满背包或将背包装至某一指定容量的方案总数。
对于这类改变问法的问题,一般只需将状态转移方程中的max改成sum即可。例如若每件物品均是完全背包中的物品,转移方程即为
f[i][v]=sum{f[i-1][v],f[i][v-c[i]]}
初始条件f[0][0]=1。
事实上,这样做可行的原因在于状态转移方程已经考察了所有可能的背包组成方案。
引用了DD大牛的《背包九讲》后的相关解释。
具体代码方面可以参考这篇
http://www.cnblogs.com/acmer-roney/archive/2013/03/04/2942601.html
方法四 母函数
母函数没有相关研究,留坑后补。有会的还望赐教。