母函数模板解释

感谢:母函数模板解释

母函数模板解释

母函数模板 
1;母函数应用于——————形式上说,普通型生成函数用于解决多重集的组合问题,而指数型母函数用于解决多重集的排列问题.。现在我们先讨论普通生成函数;

2;定义; 
(1+x)^n = 1 + C(n,1)x +C(n,2)x^2 + C(n,3)x^3+~~~~~~~~~+C(n,n)^n; 
==> G(x)=a0 + a1x + a2x^2 + ~~~~~ + anx^n;

函数G(X)就称序列a0,a1,a2,a3~~~~~an的母函数; 
看一个经典的例子;

例一; 
有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?每种重量各有几种可能方案? 
考虑用母函数来解决这个问题:

我们假设x表示砝码,x的指数表示砝码的重量,这样: 
1个1克的砝码可以用函数1+x表示, 
1个2克的砝码可以用函数1+x∧2表示, 
1个3克的砝码可以用函数1+x∧3表示, 
1个4克的砝码可以用函数1+x∧4表示

解释;以1+x∧2为例; 
2克的砝码有两种状态,取or不取; 1*x^0+1*x^2;就是1+1*x^2; 
看联系;G(x) = (1+x^1)(1+x^2)(1+x^3)*(1+x^4);每个括号内都表示每种砝码的情况。 
=1+x+x^2+2*x^3+2*x^4+2*x^5+2*x^6+2*x^7+x^8+x^9+x^10;

从最后面的式子可以知道;可以称出1g到10g,前面的系数就是方案数。指数表示可以称出的重量。 
列如5g就找到x系数为5的式子;2*x^5系数为2则有2种方案可以称出5g;

例二; 
用1分,2分,3分的邮票可以贴出数值的方案数。 
该例子对比例一的区别,这里是无限的每种邮票都可以;1~无限。 
=======G(x)=(1+x+x^2+x^3+……)(1+x^2+x^4+x^6……)(1+x^3+x^6+x^9……)+( ……); 
然后就是同样的, 
拆开后;前面的系数就是方案数。指数表示可以称出的重量。

对于这种母函数的应用应该懂了吧。 
个人理解;就是一句话,把每种列子的每种情况列出相乘就是要求的母函数了,母函数拆开之后就是结果了,幂表示情况,前面的系数表示该种情况下的方案种类;

现在我们考虑的是怎么用代码实现例二的情况呢。就是说我要怎么用用代码实现,输入一个数可以输出这种重量的方案数。 
一位大牛说,我们怎么笔算的就用这种思维去实现,然而……还是不会。

先说一下核心思路吧。 
**1;要开两个数组,c1,c2; 
C1;保存当前得到的多项式各式系数; 
C2;保存每次计算是的临时结果; 
并且在之后每计算一次完毕之后就要把c2赋值给c1,并且将c2初始化为0; 
2;三重循环 
第一重;记录它正在与第几个多项式相乘。 
第二重;表示c1中每一项; 
第三重;被后面相乘的每一项**。

在根据这些去落实代码吧;

while(scanf("%d",&n) != EOF){
        for(i = 0; i <= n; i++){//初始化;要注意并不是每次都是这样初始化的。
            c1[i] = 1;
            c2[i] = 0;
        }
        for(i = 2; i <= n; i++){
            for(j = 0; j <= n; j++){
                for(k = 0; k+j <= n; k += i){ //这里的k+=i表示的是表达式i中幂的变化规律。刚好是加i;注意适当变化。
                    c2[k+j] += c1[j];
                }
            }
            for(j = 0; j <= n; j++){
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        printf("%d
",c1[n]);
    }
;

分析代码; 
1;

 for(i = 0; i <= n; i++){

//初始化;要注意并不是每次都是这样初始化的。

c1[i] = 1; c2[i] = 0; } 

初始化;这样初始化的条件是每项都有从1到n克都存在的情况下,不能存在中间有一项没有这种情况。 
列如例子2082就是不能这样的,他中间存在没有的情况。

2;三重循环;

for(i = 2; i <= n; i++){//表示第i个表达式;
            for(j = 0; j <= n; j++){//表示、c1中的每一项。结果是幂;
                for(k = 0; k+j <= n; k += i){ //表示与第i个表达式中的幂为k的项相乘;
                    c2[k+j] += c1[j];//这里是累加。

看另外一种模板;代码出自于杭电2082;

memset(c1, 0, sizeof(c1));
memset(c2, 0, sizeof(c2));
c1[0]=1;//有些是0,则不能套用模板中的都等于1;
        //c1[0]=1;相当于入口、 
        for(i = 1; i <= 26; i++){ 
            for(j = 0; j <= 50; j++){//c1的各项的指数
                for(k = 0; k <= x[i] && j+k*i <= 50; k++){ 
                    c2[j+k*i] += c1[j];
                }//这里的k表示表达式中的第k项,并且该项的幂是k*i;  
            }
            for(j = 0; j <= 50; j++){
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }

对比一下上个代码; 
区别; 
1;初始化那里不同,这里只是c1[0]=1;而不是全部初始化为1;因此这样的初始化适用范围更广,可以是连续的情况。 
2;第三重循环那里不同,不再是k+=I;而是k++了。然而这里的区别很大,。 
这里的k表示的是第i个表达式中的第k项,并且该项的幂是k*i**; 
前面那个代码k表示的是与第i个表达式中的幂为k的项相乘。 
一个表示k项一个表示幂为k,这里注意区分

原文地址:https://www.cnblogs.com/kimsimple/p/6714516.html