普通型母函数原理及模板代码详解

母函数有很多种,最常用的有普通型母函数和指数型母函数。两者区别是:普通型母函数主要是来求组合的方案数,而指数型母函数是求多重排列数。下面只讲解普通型母函数的相关知识。


定义

若函数G(x)=a0+a1*x+a2*x^2+……+an*x^n,则称函数G(x)为序列a0、a1、a2、……an的母函数。


例如:(1+x)^n=1+C(n,1)*x+C(n,2)*x^2+……+C(n,n)*x^n 就是序列 C(n,1)、C(n,2)、……、C(n,n)的母函数,其中C(n,m)为组合数。


经典例题

有质量为1,2,4的砝码分别为1,3,2枚,问:

1.可以称出多少种不同的质量?

2.要称出质量为3的物品,有几种可能的方式?


则可以构造函数G(x) = (1+x)*(1+x^2+x^4+x^6)*(1+x^4+x^8),其中第一个括号中的1表示质量为1的砝码用了0枚,x表示质量为1的砝码用了1枚;第二个括号中的1表示质量为2的砝码用了0枚,x^2为质量为2的砝码用了1枚,x^4表示质量为2的砝码用了2枚,也就是x^(2*2),x^6表示质量为2的砝码用了3枚,也就是x^(2*3)。先不必理解为什么这样做,只需要知道怎样做。


总结一下,每个括号就表示一种砝码的使用情况。x^n就表示质量为n的砝码用了1枚。最少可以使用0枚,也就是式子里面的1。最多可以使用m枚,也就是x^(n*m)。


知道了对应关系,那么代码应该怎么写呢?其实也简单,就是模拟手动计算以上多项式相乘的过程。比如上面的

G(x) = (1+x)*(1+x^2+x^4+x^6)*(1+x^4+x^8)

= (1+x^2+x^4+x^6  + x+x^3+x^5+x^7)*(1+x^4+x^8)

= (1+x+x^2+x^3+x^4+x^5+x^6+x^7)*(1+x^4+x^8)

= (1+x+x^2+x^3+x^4+x^5+x^6+x^7  +  x^4+x^5+x^6+x^7+x^8+x^9+x^10+x^11  +  x^8+x^9+x^10+x^11+x^12+x^13+x^14+x^15)

=1+x+x^2+x^3+2*x^4+2*x^5+2*x^6+2*x^7+2*x^8+2*x^9+2*x^10+2*x^11+x^12+x^13+x^14+x^15


由于不太熟悉怎么插入数学公式,搞的上面的式子看起来有点难受……以上过程也就是不断的计算前 i 个多项式相乘的结果。最后得到的式子中 m*x^n 就表示可以有m种方式称出质量为n的物品。一共有x~x^15个不同的质量,也就是最多能称出15中不同质量的物品。


下面先给出模板代码,并讲解代码的含义:


#define MAXN 55
int a[MAXN],b[MAXN];
int s[MAXN],e[MAXN],v[MAXN];

void mu(int n)
{ //n为因子个数 
	int i,j,k;
	memset(a,0,sizeof(a));
	a[0]=1;
	for(i=1;i<=n;i++)
	{ //前i项相乘 
		memset(b,0,sizeof(b));
		//j为第i种物品可能的数量,j*v[i]即第i个括号中第j项的系数
		for(j=s[i];j<=e[i]&&j*v[i]<=MAXN;j++)
			for(k=0;k+j*v[i]<=MAXN;k++) //计算对前i-1项相乘的结果的第k项的系数产生的影响 
				b[k+j*v[i]]+=a[k];
		memcpy(a,b,sizeof(b)); //将b数组存回a数组 
	}	
}

以上代码中MAXN为结果可能生成的x的指数的最大值。

a数组存储最终结果,b数组存储中间结果
s[i] (start数组)为第i个变量的最小个数,一般都为0,e[i] (end数组)为第i个变量的最大个数
v[i]表示第i个未知量的取值,即x^v[i]
a[i]存储的是未知量 x^i 前面的系数


也就是a存储前i-1项的相乘结果,然后遍历第i项中的每一个变量,让其与a中的每一项相乘,将结果临时存储到b数组中,最后存回a数组。


例如:求不同个数的不同质量的砝码可以组成的质量为 i 的种类数
v[i]存第i种砝码质量,s[i]存第i种砝码最小的个数,e[i]存第i种砝码最大的个数,a[i]存可以组成的质量为i的种类数

最后给出个例题及我写的解析:HDU 1028

C++这个词在中国大陆的程序员圈子中通常被读做“C加加”,而西方的程序员通常读做“C plus plus”,“CPP”或者“dev.cpp"。 它是一种使用非常广泛的计算机编程语言。C++是一种静态数据类型检查的,支持多重编程范式的通用程序设计语言。它支持过程化程序设计、数据抽象、面向对象程序设计、制作图标等等泛型程序设计等多种程序设计风格。   C++ 是C语言的一个高级版本,支持中文,界面高级,不需要启动母文件即可运行程序。   美国AT&T贝尔实验室的本贾尼·斯特劳斯特卢普(Bjarne Stroustrup)博士在20世纪80年代初期发明并实现了C++(最初这种语言被称作“C with Classes”)。一开始C++是作为C语言的增强版出现的,从给C语言增加类开始,不断的增加新特性。虚函数(virtual function)、运算符重载(operator overloading)、多重继承(multiple inheritance)、模板(template)、异常(exception)、RTTI、名字空间(name space)逐渐被加入标准。1998年国际标准组织(ISO)颁布了C++程序设计语言的国际标准ISO/IEC 14882-1998。C++是具有国际标准的编程语言,通常称作ANSI/ISO C++。1998年是C++标准委员会成立的第一年,以后每5年视实际需要更新一次标准,下一次标准更新将是在2009年,目前我们一般称该标准C++0x。遗憾的是,由于C++语言过于复杂,以及他经历了长年的演变,直到现在(2004年)只有少数几个编译器完全符合这个标准(这么说也是不完全正确的,事实上,至今为止没有任何一款编译器完全支持ISO C++)。   另外,就目前学习C++而言,可以认为他是一门独立的语言;他并不依赖C语言,我们可以完全不学C语言,而直接学习C++。根据《C++编程思想》(Thinking in C++)一书所评述的,C++与C的效率往往相差在正负5%之间。所以有人认为在大多数场合C++ 完全可以取代C语言(然而我们在单片机等需要谨慎利用空间、直接操作硬件的地方还是要使用C语言)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值