定义:
对于序列a0,a1,a2,...,an,构造一个函数:
称G(x)为序列a0,a1,a2,...,an的生成函数(或者母函数)。G(x) = a0+a1*x+a2*x^2+...+an*x^n
用途:
1.“把组合问题的加法法则和幂级数的乘幂对应起来”
2.“母函数的思想很简单 — 就是把离散数列和幂级数一 一对应起来,把离散数列间的相互结合关系对应成为幂级数间的运算关系,最后由幂级数形式来确定离散数列的构造. “
相关blog:
普通母函数:http://www.wutianqi.com/?p=596
指数型母函数:http://www.wutianqi.com/?p=2644
实现:
普通母函数(适用于组合问题)
问题:设有n种砝码,每种砝码的重量由数组a[n]表示,每种砝码的个数用数组b[n]表示,求称重量为m的物体有多少种方案?
由题可以列出母函数表达式:
题目的解为G(x)的幂次为m的项系数。
int GeneratingFunction(int a[], int b[], int n, int m) { int N = 0; for(int i=0; i<n; ++i) N += a[i]*b[i]; int *value = new int[N]; int *temp = new int[N]; if(!value || !temp) { cout << "Out of memory!" << endl; return -1; } memset(temp, 0, N*sizeof(int)); memset(value, 0, N*sizeof(int)); fill(value, value+b[0]+1, 1); int max_power_cnt = b[0]*a[0]; //逐项展开 for(int i=1; i<n; ++i) { for(int j=0; j<=max_power_cnt; ++j) for(int k=0; k<=b[i]*a[i]; k+=a[i]) temp[k+j] += value[j]; max_power_cnt += b[i]*a[i]; memcpy(value, temp, max_power_cnt*sizeof(int)); memset(temp, 0, N*sizeof(int)); } int r = value[m]; delete [] value; delete [] temp; return r; }
例:(1)设有重量为1,2,3,4的砝码各一个,某物体重量为5,求称该物体有几种组合方式?
(2)将整数10拆分,有多少种方案?int a[4] = {1,2,3,4}; int b[10] = {1,1,1,1}; cout << GeneratingFunction(a, b, 4, 5) << endl;
int a[10] = {1,2,3,4,5,6,7,8,9,10}; int b[10] = {10,10,10,10,10,10,10,10,10,10}; cout << GeneratingFunction(a, b, 10, 10) << endl;
指数型母函数(适用于排列问题)
问题:有n种不同颜色的球,每种颜色的球的个数用数组a[n]表示,问取m个球进行排列,有多少种方案?
问题:有n种不同颜色的球,每种颜色的球的个数用数组a[n]表示,问取m个球进行排列,有多少种方案?
由题可以列出母函数表达式:
题目的解为G(x)的幂次为m的项系数。
#define MAX 50 double value[MAX],temp[MAX]; int fac(int i) { if(i==0) return 1; return i*fac(i-1); } int GeneratingFunctionE(int a[], int n, int m) { int N = 0; for(int i=0; i<n; ++i) N += a[i]; if(N>MAX) { cout << "Out of memory!" << endl; return -1; } memset(temp, 0, MAX*sizeof(double)); memset(value, 0, MAX*sizeof(double)); for(int i=0; i<=a[0]; ++i) value[i] = 1/(double)fac(i); int max_power_cnt = a[0]; //逐项展开 for(int i=1; i<n; ++i) { for(int j=0; j<=max_power_cnt; ++j) for(int k=0; k<=a[i]; k++) temp[k+j] += value[j]/(double)fac(k); max_power_cnt += a[i]; memcpy(value, temp, (max_power_cnt+1)*sizeof(double)); memset(temp, 0, MAX*sizeof(double)); } return (int)(value[m]*fac(m)); }
例:有红球三个,白球两个、黄球三个,去除7个球的排列数为多少?
int a[3] = {3,2,3}; cout << GeneratingFunctionE(a, 3, 7) << endl;