生成函數(母函數)入門詳解
本文章從以上兩位大佬的博客參考而來!再次感謝!
母函數,又稱生成函數,是ACM競賽中經常使用的一種解題算法,常用來解決組合方面的題目。
在數學中,某個序列的母函數(Generating function,又稱生成函數)是一種形式冪級數,其每一項的系數可以提供
關於這個序列的信息。使用母函數解決問題的方法稱為母函數方法。
母函數可分為很多種,包括普通母函數、指數母函數、L級數、貝爾級數和狄利克雷級數。對每個序列都可以寫出以
上每個類型的一個母函數。構造母函數的目的一般是為了解決某個特定的問題,因此選用何種母函數視乎序列本身的
特性和問題的類型。
這裏先給出兩句話
1.“把組合問題的加法法則和冪級數的乘冪對應起來”
2.“母函數的思想很簡單 — 就是把離散數列和冪級數一 一對應起來,把離散數列間的相互結合關系對應成為冪級數間的
運算關系,最後由冪級數形式來確定離散數列的構造. “
我們首先來看下這個多項式乘法:
母函數圖(1)
由此可以看出:
1.x的系數是a1,a2,…an 的單個組合的全體。
2. x^2的系數是a1,a2,…a2的兩個組合的全體。
………
n. x^n的系數是a1,a2,….an的n個組合的全體(只有1個)。
進一步得到:
母函數圖(2)
母函數的定義
對於序列a0,a1,a2,…構造一函數:
母函數圖(3)
稱函數G(x)是序列a0,a1,a2,…的母函數。
第一種:
有1克、2克、3克、4克的砝碼各一枚,能稱出哪幾種重量?每種重量各有幾種可能方案?
考慮用母函數來解決這個問題:
我們假設x表示砝碼,x的指數表示砝碼的重量,這樣:
1個1克的砝碼可以用函數1+1*x^1表示,
1個2克的砝碼可以用函數1+1*x^2表示,
1個3克的砝碼可以用函數1+1*x^3表示,
1個4克的砝碼可以用函數1+1*x^4表示,
上面這四個式子懂嗎?
我們拿1+x^2來說,前面已經說過,x表示砝碼,x的指數表示砝碼的重量!初始狀態時,這裏就是一個質量為2的砝碼。
那麽前面的1表示什麽?按照上面的理解,1其實應該寫為:1*x^0,即1代表重量為2的砝碼數量為0個。
所以這裏1+1*x^2 = 1*x^0 + 1*x^2,即表示2克的砝碼有兩種狀態,不取或取,不取則為1*x^0,取則為1*x^2
不知道大家理解沒,我們這裏結合前面那句話:
“把組合問題的加法法則和冪級數的乘冪對應起來“
接著討論上面的1+x^2,這裏x前面的系數有什麽意義?
這裏的系數表示狀態數(方案數)
1+x^2,也就是1*x^0 + 1*x^2,也就是上面說的不取2克砝碼,此時有1種狀態;或者取2克砝碼,此時也有1種狀態。(分析!)
所以,前面說的那句話的意義大家可以理解了吧?
幾種砝碼的組合可以稱重的情況,可以用以上幾個函數的乘積表示:
(1+x)(1+x^2)(1+x^3)(1+x^4)
=(1+x+x^2+x^4)(1+x^3+^4+x^7)
=1 + x + x^2 + 2*x^3 + 2*x^4 + 2*x^5 + 2*x^6 + 2*x^7 + x^8 + x^9 + x^10
從上面的函數知道:可稱出從1克到10克,系數便是方案數。(!!!經典!!!)
例如右端有2^x^5 項,即稱出5克的方案有2種:5=3+2=4+1;同樣,6=1+2+3=4+2;10=1+2+3+4。
故稱出6克的方案數有2種,稱出10克的方案數有1種 。
接著上面,接下來是第二種情況:
第二種:
求用1分、2分、3分的郵票貼出不同數值的方案數:
大家把這種情況和第一種比較有何區別?第一種每種是一個,而這裏每種是無限的。
母函數圖(4)
以展開後的x^4為例,其系數為4,即4拆分成1、2、3之和的拆分方案數為4;
即 :4=1+1+1+1=1+1+2=1+3=2+2
母函數通常解決類似如下的問題:
給5張1元,4張2元,3張5元,要得到15元,有多少種組合?
某些時候會規定至少使用3張1元、1張2元、0張5元。
某些時候會規定有無數張1元、2元、5元。
……
解題過程
解題時,首先要寫出表達式,通常是多項的乘積,每項由多個x^y組成。如(1+x+x^2)(1+x^4+x^8)(x^5+x^10+x^15)。
通用表達式為
(x^(v[0]*n1[0])+x^(v[0]*(n1[0]+1))+x^(v[0]*(n1[0]+2))+...+x^(v[0]*n2[0]))
(x^(v[1]*n1[1])+x^(v[1]*(n1[1]+1))+x^(v[1]*(n1[1]+2))+...+x^(v[1]*n2[1]))
...
(x^(v[K]*n1[K])+x^(v[K]*(n1[K]+1))+x^(v[K]*(n1[K]+2))+...+x^(v[K]*n2[K]))
K對應具體問題中物品的種類數。
v[i]表示該乘積表達式第i個因子的權重,對應於具體問題的每個物品的價值或者權重。
n1[i]表示該乘積表達式第i個因子的起始系數,對應於具體問題中的每個物品的最少個數,即最少要取多少個。
n2[i]表示該乘積表達式第i個因子的終止系數,對應於具體問題中的每個物品的最多個數,即最多要取多少個。
對於表達式(1+x+x^2)(x^8+x^10)(x^5+x^10+x^15+x^20),v[3]={1,2,5},n1[3]={0,4,1},n2[3]={2,5,4}。
解題的關鍵是要確定v、n1、n2數組的值。
通常n1都為0,但有時候不是這樣。
n2有時候是無限大。
通用模板:
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stack> 5 #include<queue> 6 #include<iostream> 7 #include<map> 8 #include<vector> 9 #define Inf 0x3f3f3f3f 10 #define PI acos(-1.0) 11 using namespace std; 12 const int MXAN=300+10; 13 int dp[1234]; 14 int str[1234]; 15 int main() 16 { 17 int m,n,i,j,pos; 18 int a[MXAN]; 19 int b[MXAN]; 20 while(cin>>n&&n) 21 { 22 for(int i=0;i<=300;i++) 23 { 24 a[i]=1; 25 b[i]=0; 26 } 27 for(int i=2;i<=17;i++) 28 { 29 for(int j=0;j<=n;j++) 30 { 31 for(int k=0;k+j<=n;k+=i*i) 32 { 33 b[k+j]+=a[j]; 34 } 35 } 36 for(int j=0;j<=n;j++) 37 { 38 a[j]=b[j]; 39 b[j]=0; 40 } 41 } 42 cout<<a[n]<<endl; 43 } 44 return 0; 45 }
我們來解釋下上面標誌的各個地方:(***********!!!重點!!!***********)
① 、首先對c1初始化,由第一個表達式(1+x+x^2+..x^n)初始化,把質量從0到n的所有砝碼都初始化為1.
② 、 i從2到n遍歷,這裏i就是指第i個表達式,上面給出的第二種母函數關系式裏,每一個括號括起來的就是一個表達式。
③、j 從0到n遍歷,這裏j就是(前面幾個表達式累乘的表達式)裏第j個變量,如(1+x)(1+x^2)(1+x^3),j先指示的是1和x的系數,i=2執行完之後變為
(1+x+x^2+x^3)(1+x^3),這時候j應該指示的是合並後的第一個括號的四個變量的系數。④ 、 k表示的是第j個指數,所以k每次增i(因為第i個表達式的增量是i)。
⑤ 、把c2的值賦給c1,而把c2初始化為0,因為c2每次是從一個表達式中開始的。
生成函數(母函數)入門詳解