母函数总结
观自 http://blog.csdn.net/metalseed/article/details/8046656#
所谓母函数就是:将任意一个数列,a0,a1,a2……an 通过一个函数进行联系起来。
G(n)=a0+a1*x+a2*x^2+……an*x^n; 称G(n)为数列的生成函数又叫母函数
例如现在要从四个人中选出n个人来,那么她的母函数为G(x)= 1+4x+6x^2+4x^3+x^4,实际上就是二项式展开式,也就是(1+x)^4的展开式。关于展开式还有一个广义的公式 C(k,i)= k(k-1)(k-2)(k-i+1)/i!,这个公式不只作用于整数部分,在负数小数部分同样适用。
母函数看的少点,还没有彻底理解,只能通过样例来讲解。如下:
现在有面值1,2,3,4的金币各一个,让你求出所有能组成的金额,并且算出组成金额的方案数。
现在假设x表示砝码,x的指数表示金币的金额,得到:(1+x)表示一个金币1,(1+x^2)表示一个金币2,(1+x^3)表示一个金币3,(1+x^4)表示一个金币4。
这里这几个函数不好理解,这个1不是单纯的1,其实每个函数都是由a x^n表示的,
指数n表示的是金币的金额,系数a表示金额n的金币拿多少,那么就拿(1+x)来说吧,他表示两个意思一个就是1*x^0也就是金额为零的金币拿一个,1*x^1就是金额为一的金币拿一个。实际上每个括号里函数表示的就是,相应金额的金币,拿与不拿。这样按照组合数学的思想就囊括了所有的情况。
那么得到母函数G(n)= (1+x)* (1+x^2) *(1+x^3)* (1+x^4)。
化简得到G(n)= 1+x+x^2+2x^3+2x^4+2x^5+2x^6+2x^7+x^8+x^9+x^10;
这样得出金额为1-10组成方案数,分别为{1,1,2,2,2,2,2,,1,1,1}.
这个方案按照组合代数的方法在纸上好实现,那么在代码中怎么实现呐?如下代码
#include <iostream> using namespace std; const int _max = 10001; // c1是保存各项质量砝码可以组合的数目 // c2是中间量,保存每一次的情况 int c1[_max], c2[_max]; int main(){ int nNum; //你要查询组合数的金额 int i, j, k; while(cin >> nNum){ for(i=0; i<=nNum; ++i){ // —- ① 首先对c1初始化,由第一个表达式(1+x+x2+..xn)初始化,把质量从0到n的所有砝码都初始化为1. c1[i] = 1; c2[i] = 0; } for(i=2; i<=nNum; ++i){ // —– ② i从2到n遍历,这里i就是指第i个表达式,上面给出的第二种母函数关系式里,每一个括号括起来的就是一个表达式。 for(j=0; j<=nNum; ++j) // —– ③j从0到n遍历,这里j就是只一个表达式里第j个变量,比如在第二个表达式里:(1+x2+x4….)里,第j个就是x2*j. for(k=0; k+j<=nNum; k+=i){ // —- ④//k表示的是第j个指数,所以k每次增i(因为第i个表达式的增量是i)。 c2[j+k] += c1[j]; } for(j=0; j<=nNum; ++j){ // —- ⑤把c2的值赋给c1,而把c2初始化为0,因为c2每次是从一个表达式中开始的 c1[j] = c2[j]; c2[j] = 0; } } cout << c1[nNum] << endl; } /* ( 最外层,记录它正在与第几个多项式相乘。第二层,表示c1中的每一项,第三层表示后面被乘多项式中的每一项。) */ return 0; }