母函数
简单介绍
定义:
对于序列a0,a1,a2,a3…an构造一个函数:
G(x)=a0+a1x+a2x2+a3x3+…
称函数G(x)是序列a0,a1,a2,a3…an的母函数。
举例:
以选砝码为例,母函数就是利用次幂来表示面值和数量,例如:(1+x)用来表示1个1克的砝码,(1+x2)用来表示1个2克的砝码,(1+x3)用来表示1个3克的砝码,(1+x4)用来表示1个4克的砝码。
表示这几个砝码的组合情况时,只要将各个式子乘起来就OK了。例子中的四个式子相乘我们可以得到1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10,每个项的系数就表示每一种的组合情况,比如3,可以选1和2,也可以选一个3;而对于2,只能选一个2。
关键点:
实现对多项式的展开。
代码模板
这里需要说一下拆分数的概念:整数拆分成若干整数的和不同的拆分法的总数叫做拆分数,该代码就是求整数n的拆分数的。
#include<iostream>
#include <bits/stdc++.h>//母函数一般用来解决整数拆分、邮票组合、砝码称重一类的问题
#define lmax 1000//该例子是以整数拆分为例的母函数代码,即读入一个n,求这个数的拆分数
using namespace std;
int c1[lmax],c2[lmax];
int elem[lmax];//当给定的数值没有规律时,可以直接用数组存储,用下标取数
int main()//普通型母函数模板
{
int n,i,j,k;
while(cin>>n)
{
for(i=0;i<=n;i++)
{
c1[i]=0;
c2[i]=0;
}
for(i=0;i<=n;i++)
{
c1[i]=1;
}
for(i=2;i<=n;i++)//关键的三层for循环,总共有n个括号,做n-1趟for循环
{
for(j=0;j<=n;j++)//c1数组表示当前括号,c2数组表示当前的下一个括号,两层for循环遍历一遍
for(k=0;k+j<=n;k+=i)
{
c2[j+k]+=c1[j];
}
for(j=0;j<=n;j++)//将循环得到的值赋给c1数组
{
c1[j]=c2[j];
c2[j]=0;
}
}
cout<<c1[n]<<endl;
}
return 0;
}
指数型母函数
母函数解决的是组合型问题,而指数型母函数解决的则是排列型问题。
代码模板
#include<iostream>
#include <bits/stdc++.h>//指数型母函数一般用来解决组合一类的问题
using namespace std;
const int lmax=21;//因为涉及到阶乘,因此数据量一般不会很大
double c1[lmax],c2[lmax];
int val[lmax],F[lmax];
void factorial()//将阶乘的结果存到F数组中
{
F[0]=1;
for(int i=1;i<=20;i++)
{
F[i]=F[i-1]*i;
}
}
int main()//指数型母函数模板
{
int n,m,i,j,k;
factorial();
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++)
{
scanf("%d",&val[i]);
}
for(i=0;i<=n;i++)
{
c1[i]=0;
c2[i]=0;
}
//memset(c1,0,sizeof(c1));//这里的初始化可以用memset来写
//memset(c2,0,sizeof(c2));
for(i=0;i<=val[0];i++)
{
c1[i]=1.0/F[i];
}
for(i=2;i<=n;i++)//关键的三层for循环,总共有n个括号,做n-1趟for循环
{
for(j=0;j<=m;j++)//c1数组表示当前括号,c2数组表示当前的下一个括号,两层for循环遍历一遍
for(k=0;k+j<=m&&k<=val[i];++k)
{
c2[j+k]+=c1[j]/F[k];
}
for(j=0;j<=m;j++)//将循环得到的值赋给c1数组
{
c1[j]=c2[j];
c2[j]=0;
}
}
printf("%.0f\n",c1[m]*F[m]);
}
return 0;
}
母函数这一边很多东西都需要很多实践才能理解地更加透彻,我也是在不断的摸索中写出的着一些东西,还有很多不足。