现有币值为1分,5分,10分,25分和50分的硬币,各种硬币可以任意取整数枚,也可以不取,问有多少种方法可以使所取的硬币的总币值为1元。
这是个典型的组合数学问题,可以构造生成函数,然后求出某项的系数来得到结果。
生成函数的原理基于加法变乘法,即 xa+b+c+d...=xa⋅xb⋅xc⋅xd...
具体到我们现在这个题,题目是求 1⋅a+5⋅b+10⋅c+25⋅d+50⋅e=100 有多少非负整数解?
对于1分的情况,可构造级数
1+x+x2+x3+...
对于5分的情况,可构造级数
1+x5+x10+x15+...
对于10分的情况,可构造级数
1+x10+x20+x30+...
对于25分的情况,可构造级数
1+x25+x50+x75+...
对于50分的情况,可构造级数
1+x50+x100+x150+...
整体的函数构造为
(1+x+x2+x3+...)⋅(1+x5+x10+x15+...)⋅(1+x10+x20+x30+...)⋅(1+x25+x50+x75+...)⋅(1+x50+x100+x150+...)
其中
x100
前的系数就是这个问题的解
用C语言来解决这个问题
#include <stdio.h>
#include<string.h>
int main() {
int i,j,k,MAX=100,c1[MAX+5],c2[MAX+5],num[6]={0,1,5,10,25,50};//c1保存x^0,x^1,x^2...的系数,c2为临时数组
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
c1[0]=1;//注意为代码简单,我们是从(1,0,0,0,0,0...)*(1+x+x^2+x^3+...)的(1,0,0,0,0,0)开始计算
for(i=1;i<=5;i++){//共有5个多项式相乘
for(j=0;j<=MAX;j++){//嵌套的两个for循环计算如(1+x+x^2+...)*(1+x^5+x^10+...)的系数
for(k=0;j+k*num[i]<=MAX;k++){
c2[j+k*num[i]] += c1[j];
}
}
memcpy(c1,c2,sizeof(c2));
memset(c2,0,sizeof(c2));
}
printf("%d\n",c1[MAX]);
return 0;
}