普通母函数

母函数(生成函数,Generating Function)

在看普通母函数之前,先了解一下什么是母函数,为此我们先看一个多项式:

(1+a1*x)(1+a2*x)…(1+an*x) = 1 + (a1 + a2 + …+an)x + (a1*a2 + a1*a3 + … + an-1*an)x^2 + …+ a1*a2*…*an*x^n

我们可以看出:

(1) x项的系数是从n个元素(a1,a2,…,an)中取一个元素组合的全体,有C(n,1)个。

(2)x^2项的系数是从n个元素(a1,a2,…,an)中取两个元素组合的全体,有C(n,2)个。

(n)x^n项的系数是n个元素(a1,a2,…,an)中取n个元素组合的全体,有C(n,n)个。

那么,如果将a1,a2,…,an均设为1,可以得到:(1+x)^n = 1 + C(n,1)*x + C(n,2)*x^2 + …+C(n,n)*x^n。

同时给出母函数的定义:对于序列a0,a1,a2,…,an构造一函数G(x) = a0 + a1*x + a2*x^2 + … + an*x^n,那么我们称函数G(x)是序列a0,a1,a2,…,an的母函数。

普通母函数

在这里,给出一个普通母函数的模型,并对此进行详解:

现有属性为1,2,3的物品各1个,可以组成多少种不同属性?每种组成属性的组成方案有几种?

假设用x表示物品,x的指数表示属性,可以得到:

1个属性为1的物品可以用表达式 1 + x 表示,1表示可以不用属性为1的物品,x表示可以用属性为1的物品。

1个属性为2的物品可以用表达式 1 + x^2表示,1表示可以不用属性为2的物品,x^2表示可以用属性为2的物品。

1个属性为3的物品可以用表达式 1 + x^3表示,1表示可以不用属性为3的物品,x^3表示可以用属性为3的物品。

于是我们可以构造母函数如下:

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

至此,属于该模型的母函数已经构造出来,其实际意义是x的指数表示组成属性的值,系数为某种属性的组成方案有几种。例如上式中的2*x^3其意义就是组成属性为3的方案有2种。

那么,如果说不同属性值的物品都有2个,我们便可以得到下述母函数:

G(x) = ( 1 + x + x^2 )(1 + x^2 + x^4 )(1 + x^3 + x^6 )。为了在下面能够对母函数有一个更好的叙述,现将每一个幂指数化为Howey所说的标准形式即 (x^i)^j。可化为如下形式:

G(x) = [ (x^1)^0 + (x^1)^1 + (x^1)^2  ]*[ (x^2)^0 + (x^2)^1 + (x^2)^2 ]*[ (x^3)^0 + (x^3)^1 + (x^3)^2 ],在此,我们将每一个中括号所包含的内容称为一个表达式,在每一个表达式中将 i 替换掉的值代表是第几个表达式(很凑巧的是与给出的模型当中所要代表的属性值一直,其实实质上也表达了采用了第几个属性值),将 j 替换掉的值代表使用某种属性值的数量。例如:

(x^2)^0其中2就是标准形式中的i,0就是标准形式中的j,其具体意义是可以使用0个第二个属性值(在该模型中属性值也为2)的物品,现在应该明白母函数中“1”的来历了吧。

(x^3)^2其中3就是标准形式中的i, 2就是标准形式中的j,其具体意义是可以使用2个属性值为2的物品。

如果真正理解上述内容,请用笔写出不同属性值物品有n个时候的标准形式(这对真正理解下面所要介绍的代码十分关键,同时也能帮助大家对代码的改写做到举一反三有所帮助!!!)。

在这里给出不同属性值物品有n个的代码:

 1 int x[MAX],c[MAX];

 2 //数组x的值代表组成某种属性的数目

 3 //c用来得到x的中间变量

 4 

 5 int GeneratingFunction(int n,int m,int value)

 6 {

 7     //n代表有多少种不同的属性

 8     //m代表每种属性的个数

 9     //value代表组成属性值为value

10 

11     memset(x,0,sizeof(x));

12     memset(c,0,sizeof(c));

13 

14     for(int j = 0 ; j <= m; j++)

15     {   //j代表表达式中的第j项

16         x[j] = 1;

17     }

18 

19     for(int i = 2 ; i <= n; i++)

20     {

21         //i代表第i个表达式

22         //(将要与第i个表达式之前的

23         //所有表达式累乘后的结果表

24         //达式相乘)

25         for(int j = 0 ; j <= value ; j++)

26         {

27             //j代表第i个表达式之前累乘

28             //得到的表达式中组合属性值

29             //为j的项

30             for(int k = 0; k <= m ; k++)

31             {   //k代表当前表达式中第k项

32                 if( (k * i + j) > value)

33                     break;

34                 c[k * i + j] += x[j];

35             }

36         }

37 

38         for(int t = 0; t <= value ; t++)

39         {

40             x[t] = c[t];

41             c[t] = 0;

42         }

43     }

44 

45     return x[value];

46 }

最后在这总结一下上述代码,其核心在于三层循环,第一层循环代表当前所要乘的表达式,第二层循环代表之前所有表达式乘积中各组成属性的值,第三层循环代表当前所要成的表达式的第k项。如果对该过程还不是很明白的话,不放将不同属性值各n个的这种情况写成标准形式,然后展开后看看(其实质就是模拟对母函数这个多项式的展开,只不过在此值限制在了组成属性值(即x的指数)到value而已)。

 

参考资料:

1.组合数学及应用(周治国 编)

2.TankyWoo的个人博客 http://www.wutianqi.com/?p=596

你可能感兴趣的:(函数)