文章来自:http://blog.sina.com.cn/s/blog_8f06da990100uz2j.html
先说明一下母函数,对于序列a0,a1,a2,...构造一函数G(x)=a0+a1x+a2x^2+...,则称G(x)为a0,a1,a2...的母函数。
母函数可以解决很多计数问题,比如说有三种颜色的球各一个,问有多少种组合方式呢?41的整数划分有多少种?诸如此类的好多,这次只是讲一下解决acm中的常遇到的一种问题,我们用砝码作为模型来描述。
现在给你几种不同重量的砝码,每种砝码的数量都不同,那么用这些砝码组合成某个重量的方法数为多少呢?
一个1克砝码可以表示1种0克重量(0),1种1克重量(1);
两个1克砝码可以表示1种0克重量(0),1种1克重量(1),1种2克重量(1+1)
三个1克砝码可以表示1种0克重量(0),1种1克重量(1),1种2克重量(1+1),1种3克重量(1+1+1)
一个2克砝码可以表示1种0克重量(0),1种2克重量(2);
两个2克砝码可以表示1种0克重量(0),1种2克重量(2),1种4克重量(2+2)
三个2克砝码可以表示1种0克重量(0),1种2克重量(2),1种4克重量(2+2),1种6克重量(2+2+2)
一个m克砝码可以表示1种0克重量(0),1种m克重量(m)
n个m克砝码可以表示1种0*m克重量(0),1种1*m克重量(m),1种2*m克重量(m+m),…,1种n*m克重量(m+m…+m)
我们用函数来描述上述的情况
一个1克砝码:1*x^0+1*x^1;
两个1克砝码:1*x^0+1*x^1+1*x^2
三个1克砝码:1*x^0+1*x^1+1*x^2+1*x^3
一个2克砝码:1*x^0+1*x^2;
两个2克砝码:1*x^0+1*x^2+1*x^4
三个2克砝码:1*x^0+1*x^2+1*x^4+1*x^6
一个m克砝码:1*x^0+1*x^m;
n个m克砝码:1*x^(0*m)+1*x^(1*m)+1*x^(2*m)+1*x^(3*m)+…+1*x^(n*m)
我们把函数连乘,比如1克砝码2个,2克砝码3个,3克砝码四个,我们用函数表示为
两个1克砝码:1*x^0+1*x^1+1*x^2
三个2克砝码:1*x^0+1*x^2+1*x^4+1*x^6
四个3克砝码:1*x^0+1*x^3+1*x^6+1*x^9+1*x^12
用这些砝码可以组合多少种重量呢,就是把他们能表示的各种重量进行叠加组合,方法是这三条式子相乘。
(1*x^0+1*x^1+1*x^2)(1*x^0+1*x^2+1*x^4+1*x^6)(1*x^0+1*x^3+1*x^6+1*x^9+1*x^12)
得到a1*x^b1+a2*x^b2+a3*x^b3…+an*x^bn
这个式子可以还原为:有a1种方式组合成重量b1,有a2种方式组合成重量b2,有an种方式组合成重量bn
像求任意数量的任意砝码能组合成多少种重量或者某种重量有多少种组合方法都可以解决。
接下来是代码实现,算是模板吧
//target目标重量,n代表砝码的种数,(注意:因子不一定从1开始)
//a[i]表示重量为i的方式数,x^i的系数,设置temp[]数组来保存中间结果
//fweight[i]记录第i种砝码的重量
//fnumber[i]记录第i种砝码的数量
memset(temp,0,sizeof(temp));
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
scanf("%d%d",&fweight[i],&fnumber[i]);
for(int i=0;i<=fweight[1]*fnumber[1];i+=fweight[1])
a[i]=1;//先对第一个砝码初始化
for(int i=2;i<=n;i++)//依次将编号2到n的砝码相乘,每次相乘结果保存在a[]中
{
}