http://linjianxionggo.blog.163.com/blog/static/8532250020107310235772/
For example:
(1+x)^n是序列C(n,0),C(n,1),...,C(n,n)的母函数。
如若已知序列a0,a1,a2,…则对应的母函数G(x)便可根据定义给出。
反之,如若已经求得序列的母函数G(x),则该序列也随之确定。
序列a0,a1,a2,…可记为{an} 。
实 例 分 析
例一、若有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
如何解决这个问题呢?考虑构造母函数。
如果用x的指数表示称出的重量,则:
1个1克的砝码可以用函数1+x表示,
1个2克的砝码可以用函数1+x2表示,
1个3克的砝码可以用函数1+x3表示,
1个4克的砝码可以用函数1+x4表示
几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:
(1+x)(1+x2)(1+x3)(1+x4)
=(1+x+x2+x3)(1+x3+x4+x7)
=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10
从上面的函数知道,可称出从1克到10克,系数便是方案数。
(1+x)^n是序列C(n,0),C(n,1),...,C(n,n)的母函数。
如若已知序列a0,a1,a2,…则对应的母函数G(x)便可根据定义给出。
反之,如若已经求得序列的母函数G(x),则该序列也随之确定。
序列a0,a1,a2,…可记为{an} 。
实 例 分 析
例一、若有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?各有几种可能方案?
如何解决这个问题呢?考虑构造母函数。
如果用x的指数表示称出的重量,则:
1个1克的砝码可以用函数1+x表示,
1个2克的砝码可以用函数1+x2表示,
1个3克的砝码可以用函数1+x3表示,
1个4克的砝码可以用函数1+x4表示
几种砝码的组合可以称重的情况,可以用以上几个函数的乘积表示:
(1+x)(1+x2)(1+x3)(1+x4)
=(1+x+x2+x3)(1+x3+x4+x7)
=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10
从上面的函数知道,可称出从1克到10克,系数便是方案数。
例如右端有2x5 项,即称出5克的方案有2:5=3+2=4+1,同样,6=1+2+3=4+2;10=1+2+3+4。故称出6克的方案有2,称出10克的方案有1 .
例二、若有1元、5元、10元、20元、50元的人民币一堆,能凑出100元有几种可能方案?
如何解决这个问题呢?考虑构造母函数。
类似于非完全背包问题,
如cost[5] = {1, 5, 10, 20, 50}
num[5] = {50, 61, 23, 21, 11}
背包大小为100.
母函数构造如下:
(1+x1+x2+x3+.....+x50)*(1+x5+x10+x15+...+x305)*(1+x10+x20+...+x230)*(1+x20+x40+x60+....+x420)*(1+x50+x100+...+x550)
求最后x100的系数,即为所求。
前i个数的选择
f[i][v] = SUM( f[i-1][ v-k*cost[i]] ) (0<=k<=num[i] && v-k*cost[i]>=0)
代码如下:
cost[]={1,5,10,20,50,100};
num[]={50,61,...};
pack[101] ={0};
pack[0] =1;
for(int i = 0; i<cost.length; i++)
for(int j=100; j>=1; j--) //必须逆序
{
if(pack[j] != 0)
{
k=0;
while(k<=num[i] && j+k*cost[i] <=100)
{ a[j+k*b[i]] += a[j]; k++;
}
}
}
cout<<a[100]<<endl;
// another method
f[0]=1; //init
for(int i=0; i<cost.length; i++)
for(int v=100; v>=0; v++)
{
int times = num[i];
for(int k=v; k>=0 && times-->=0; k-=cost[i])
{
if(pack[k]==0) continue;
pack[v] += pack[k];
}
}
cout<<pack[100]<<endl;