母函數詳解
在數學中,某個序列的母函數(Generating function,又稱生成函數)是一種形式冪級數,其每一項的系數可以提供關於這個序列的信息。使用母函數解決問題的方法稱為母函數方法。
母函數———把組合問題的加法法則和冪級數的的乘冪的相加對應起來
我們從經典的砝碼的例子講起
題目:有1g 2g 3g 4g的砝碼各一枚,能稱出多少種重量?每種重量的可能組合砝碼是什麽
窮舉的話,很容易得出結果,單數時間復雜的度為n的四次方,較大,不能采取
所以,我麽可以采用一個類似離散數學的邏輯式子表示前兩種砝碼組合產生的情況
這裏 ||代表或 &&代表與
(使用1g||不使用1g)&&(使用2g||不適用2g)
=使用1g&&使用2g||不使用1g&&使用2g||使用1g&&不使用2g||不使用1g&&不使用2g
思考:大家可以發現這個表達式和一種表達式很像,沒錯,如果把“||”看成加法,“&&”看成乘法,和多項式的乘法一模一樣。那麽我們直覺的想到,有沒有可能用多項式乘法來表示組合的情況呢?我們再來看題目,題目需要的是幾種砝碼組合後的重量,是一個加法關系,但是在上式中“&&”是一種類似於乘法的運算關系,這怎麽辦呢?有沒有什麽這樣一種運算關系,以乘法的形式運算,但是結果表現出類似於加法的關系呢?正好有一個,那就是冪運算。Xm 乘上Xn結果是Xm+n,他完美的符合了我們的要求。
還是以前倆個砝碼為例說明。表示1g砝碼的兩種多項式就是(x^0+x^1),表示2g砝碼的兩種多項式就是(x^0+x^2),x的0次方表示沒有使用該砝碼,當然x的0次方等於1,所以寫成1也是對的。註意,砝碼的重量是用次數表示的,而不是用下標表示的
(x^0+x^1)*(x^0+x^2)
=x^0*x^0+x^1*x^1+x^0*x^1+x^1*x^2
=x^0+x^1+x^2+x^3
結果很顯然,有四個方案;0g 1g 2g 3g
再試試四個砝碼加一起的結果
一個1g 2g 3g 4g
(x^0+x^1)* (x^0+x^2) * (x^0+x^3)* (x^0+x^4)
=x^0 + x^1 + x^2 + 2x^3 + 2x^4 + 2x^5 + 2x^6 + 2x^7 + x^8+ x^9 + x^10
結果就是0g 1g 2g 2個3g 2個4g 2個5g 2個6g 2個7g 一個8g 一個9g 一個10g
至此也就得出了答案。這就是普通母函數,現在你可以回頭去看看我前面說的那兩句話——把組合問題的加法法則和冪級數的的乘冪的相加對應起來,把離散數列間的相互結合關系對應成為冪級數間的運算關系,最後由冪級數形式來確定離散數列的構造。
接下來我們再將題改變一下 ,不限制砝碼的數量,有無限個1g 2g 3g的砝碼,問能組成不同重量級的方案數
怎樣在母函數裏表現出無限這種性質呢?很簡單,我們以2g砝碼為例,因為我們有無限個2g砝碼,所以我們可以把2個2g砝碼看成是4g砝碼,3個2g砝碼看成是6g砝碼,依次類推,把m個n g砝碼看成是一個n*m g砝碼,還是先以前兩個砝碼為例,那麽多項式相應的就變成
(x^0 +x^1 + x^2 + x^3 + x^4 + x^5 + …… )*(x^0 + x^2 + x^4 + x^6 + x^8+ x^10 + ……)
結果自然也是無限的,但是題目一般都會給出一定的限制條件
結果自然也是無限的,但是這種問題在實際問題中,一定會給出一個確定的值,比如說求組成10g的方案有幾種。那麽我們就只要在合並後的結果求到最高次的項是x10即可,後面的項可以忽略不計。那麽要結果中最高為10次方,開始每一種砝碼的無限項的表達式該寫到幾次呢?也是10次,因為表達式中最低的項有x0 ,所以想在結果中不漏掉出現x10 的項,必須乘之前的項最高的項不能小於x10,而表達式中不可能出現x-1,,所以x11 和任何一項相乘都會大於x10,所以x11 是不需要的,但寫上也無妨,不影響結果,但是如果可以有x10(比如3g的砝碼組合不出10g的,但是2g的就可以),那就必須寫,不然就會漏掉一些方案。
那麽如果題目是求用1g、2g、3g的砝碼稱出10g的方案數 。
表達式就是:
(x^0 +x^1 + x^2 + x^3 + x^4 + x^5 + ……x^10 )*(x^0 + x^2 + x^4 + x^6 + x^8+ x^10 )
結果就是合並同類項後x10的系數。
多項式乘法顯然是一種運算時間規模在n2級別的運算,但是如果循環生成無限的砝碼,也就是上面用小砝碼組合出每一種可能的大砝碼,那麽生成多項式就又需要n的規模,在此基礎上進行多項式乘法,最後無限砝碼的問題需要的運算時間規模就是n3級別。
這樣母函數就把這類組合問題從nn級別轉化成了n3級別。這便是母函數的奇妙與威力。
知道了母函數的原理,用程序來實現也就不是什麽困難的事了,其實就是做多項式乘法的程序
這個模板是所有小於t的的數的組合數的總數
例如
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
#include <iostream> using namespace std; const int maxn = 10010; int sup[maxn],temp[maxn]; int main() { int t; int i,j,k; while(cin>>t) { for(i=0;i<t;i++) { sup[i] = 1 ; temp[i] = 0; } for(i=2;i<=t;i++) { for(j=0;j<=t;j++) { for(k=0;k+j<=t;k+=i) { temp[j+k] += sup[j]; } } for(j=0;j<=t;++j) { sup[j] = temp[j]; temp[j] = 0; } } cout<<sup[t]<<endl; } return 0; }
母函數詳解