还是先给出定义:
生成函数即母函数,是组合数学中尤其是计数方面的一个重要理论和工具。(跟没说一样)
母函数在组合数学的问题中很有用,我也只知道一些皮毛,即:解决方案数的组合问题。
其他用法在以后的学习中再慢慢补充。
还是举例子说明,这样说着比较清晰:(例子不是oj上的题,纯属自己虚构)
有1元、2元、5元钱无限个,问要组成8元钱有几种方案?
首先我们来构造一元钱的多项式:
1+x+x2+x3+x4+x5+x6+x7+x8
意思是:由一元钱,取0个的方案数为1,即1x0
取1个的方案数为1,即1x1
……
取8个的方案数为1,即1x8
这个是只有1元钱的情况。
然后是两元钱的多项式:
1+x2+x4+x6+x8
根据上面的说明,应该可以理解每一项是什么意思吧。
那么五元钱的多项式为:
1+x5
是不是有那么点感觉了,然后我来说明多项式的系数和指数是什么含义:例如 b*xm这个系数b表示取m元的方案数。
然后我们把这三个多项式相乘:
得到:(真的不想算这个,我还是写程序帮我算吧)
根据刚刚的说明,我们可以知道,x的8次方的系数即为方案数,也就是7。
贴上这个题的源代码:
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; #define CLR(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define LL long long int m[3] = {1,2,5}; int t[10]; int c[10]; int main() { for (int i = 0 ; i <= 8 ; i++) //第一个数的多项式 c[i] = 1; for (int i = 1 ; i < 3 ; i++) //从第二个钱开始累计乘法 { for (int j = 0 ; j <= 8 ; j++) { for (int k = 0 ; k + j <= 8 ; k += m[i]) //乘以这种钱的价值的多项式 t[k+j] += c[j]; } for (int j = 0 ; j <= 8 ; j++) { c[j] = t[j]; t[j] = 0; } } printf ("%dx^0 ",c[0]); for (int i = 1 ; i <= 8 ; i++) printf ("+ %dx^%d",c[i],i); puts(""); return 0; }
这类问题的核心就在那几个for循环上,实际上就是模拟人运算了多项式,中间的系数用t数组存起来。这个多项式乘完后,更新c数组。
如果上面的懂了, 那么我们再看:如果每个钱数有限制呢?比如,一元有a个,两元有b个,五元有c个呢?
那么我们就改变一下每个钱对应的多项式的项数就行了。(其实上面的问题是无限项数的多项式,但是我们只要求算取8元的方案数,那么我们就算到8就行了)
那么这类问题的代码如下:
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; #define CLR(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define LL long long int m[3] = {1,2,5}; int num[3]; int t[10]; int c[10]; int main() { scanf ("%d %d %d",&num[0],&num[1],&num[2]); for (int i = 0 ; i <= 8 && i <= num[0] ; i++) //第一个数的多项式 //第一个多项式也要控制一下 c[i] = 1; for (int i = 1 ; i < 3 ; i++) //从第二个钱开始累计乘法 { for (int j = 0 ; j <= 8 ; j++) { for (int k = 0 ; k + j <= 8 && k <= num[i] * m[i] ; k += m[i]) //乘以这种钱的价值的多项式 //上面的代码和这个就多了一个这个for循环条件的控制 t[k+j] += c[j]; } for (int j = 0 ; j <= 8 ; j++) { c[j] = t[j]; t[j] = 0; } } printf ("%dx^0 ",c[0]); for (int i = 1 ; i <= 8 ; i++) printf ("+ %dx^%d",c[i],i); puts(""); return 0; } 输入1 2 3,运行结果:
