什么是生成函數?


    我們年級有許多漂亮的MM。一班有7個左右吧,二班大概有4個,三班最多,16個,四班最可憐,一個漂亮的MM都沒有,五班據說有1個。如果用一個函數“f(班級)=漂亮MM的個數”,那么我們可以把上述信息表示成:f(1)=7,f(2)=4,f(3)=16,f(4)=0,f(5)=1,等等。
    生成函數(也有叫做“母函數”的,但是我覺得母函數不太好聽)是說,構造這么一個多項式函數g(x),使得x的n次方系數為f(n)。於是,上面的f函數的生成函數g(x)=7x+4x^2+16x^3+x^5+...。這就是傳說中的生成函數了。關鍵是,這個有什么用呢?一會兒要慢慢說。我敢打賭這絕對會是我寫過的最長的一篇文章。

    生成函數最絕妙的是,某些生成函數可以化簡為一個很簡單的函數。也就是說,不一定每個生成函數都是用一長串多項式來表示的。比如,這個函數f(n)=1 (n當然是屬於自然數的),它的生成函數就應該是g(x)=1+x+x^2+x^3+x^4+...(每一項都是一,即使n=0時也有x^0系數為1,所以有常數項)。再仔細一看,這就是一個有無窮多項的等比數列求和嘛。如果-1<x<1,那么g(x)就等於1/(1-x)了。在研究生成函數時,我們都假設級數收斂,因為生成函數的x沒有實際意義,我們可以任意取值。於是,我們就說,f(n)=1的生成函數是g(x)=1/(1-x)。

    我們舉一個例子說明,一些具有實際意義的組合問題也可以用像這樣簡單的一個函數全部表示出來。
    考慮這個問題:從二班選n個MM出來有多少種選法。學過簡單的排列與組合的同學都知道,答案就是C(4,n)。也就是說。從n=0開始,問題的答案分別是1,4,6,4,1,0,0,0,...(從4個MM中選出4個以上的人來方案數當然為0嘍)。那么它的生成函數g(x)就應該是g(x)=1+4x+6x^2+4x^3+x^4。這不就是……二項式展開嗎?於是,g(x)=(1+x)^4。
    你或許應該知道,(1+x)^k=C(k,0)x^0+C(k,1)x^1+...+C(k,k)x^k;但你或許不知道,即使k為負數和小數的時候,也有類似的結論:(1+x)^k=C(k,0)x^0+C(k,1)x^1+...+C(k,k)x^k+C(k,k+1)x^(k+1)+C(k,k+2)x^(k+2)+...(一直加到無窮;式子看着很別扭,自己寫到草稿紙上吧,畢竟這里輸入數學式子很麻煩)。其中,廣義的組合數C(k,i)就等於k(k-1)(k-2)...(k-i+1)/i!,比如C(4,6)=4*3*2*1*0*(-1)/6!=0,再比如C(-1.4,2)=(-1.4)*(-2.4)/2!=1.68。后面這個就叫做牛頓二項式定理。當k為整數時,所有i>k時的C(k,i)中分子都要“越過”0這一項,因此后面C(k,k+1),C(k,k+2)之類的都為0了,與我們的經典二項式定理結論相同;不同的是,牛頓二項式定理中的指數k可以是任意實數。

    我們再舉一個例子說明一些更復雜的生成函數。n=x1+x2+x3+...+xk有多少個非負整數解?這道題是學排列與組合的經典例題了。把每組解的每個數都加1,就變成n+k=x1+x2+x3+...+xk的正整數解的個數了。教材上或許會出現這么一個難聽的名字叫“隔板法”:把n+k個東西排成一排,在n+k-1個空格中插入k-1個“隔板”。答案我們總是知道的,就是C(n+k-1,k-1)。它就等於C(n+k-1,n)。它關於n的生成函數是g(x)=1/(1-x)^k。這個生成函數是怎么來的呢?其實,它就是(1-x)的-k次方。把(1-x)^(-k)按照剛才的牛頓二項式展開,我們就得到了x^n的系數恰好是C(n+k-1,n),因為C(-k,n)*(-x)^n=[(-1)^n*C(n+k-1,n)]*[(-1)^n*x^n]=C(n+k-1,n)x^n。這里看暈了不要緊,后文有另一種方法可以推導出一模一樣的公式。事實上,我們有一個純組合數學的更簡單的解釋方法。因為我們剛才的幾何級數1+x+x^2+x^3+x^4+...=1/(1-x),那么(1+x+x^2+x^3+x^4+...)^k就等於1/(1-x)^k。仔細想想k個(1+x+x^2+x^3+x^4+...)相乘是什么意思。(1+x+x^2+x^3+x^4+...)^k的展開式中,n次項的系數就是我們的答案,因為它的這個系數是由原式完全展開后k個指數加起來恰好等於n的項合並起來得到的。

    現在我們引用《組合數學》上暴經典的一個例題。很多書上都會有這類題。
    我們要從蘋果、香蕉、橘子和梨中拿一些水果出來,要求蘋果只能拿偶數個,香蕉的個數要是5的倍數,橘子最多拿4個,梨要么不拿,要么只能拿一個。問按這樣的要求拿n個水果的方案數。
    結合剛才的k個(1+x+x^2+x^3+x^4+...)相乘,我們也可以算出這個問題的生成函數。

g(x)=(1+x^2+x^4+...)(1+x^5+x^10+..)(1+x+x^2+x^3+x^4)(1+x)
    =[1/(1-x^2)]*[1/(1-x^5)]*[(1-x^5)/(1-x)]*(1+x) (前兩個分別是公比為2和5的幾何級數,
                                                     第三個嘛,(1+x+x^2+x^3+x^4)*(1-x)不就是1-x^5了嗎)
    =1/(1-x)^2   (約分,把一大半都約掉了)
    =(1-x)^(-2)=C(1,0)+C(2,1)x+C(3,2)x^2+C(4,3)x^3...   (參見剛才對1/(1-x)^k的展開)
    =1+2x+3x^2+4x^3+5x^4+....


    於是,拿n個水果有n+1種方法。我們利用生成函數,完全使用代數手段得到了答案!
    如果你對1/(1-x)^k的展開還不熟悉,我們這里再介紹一個更加簡單和精妙的手段來解釋1/(1-x)^2=1+2x+3x^2+4x^3+5x^4+....。
    1/(1-x)=1+x+x^2+x^3+x^4+...是前面說過的。我們對這個式子等號兩邊同時求導數。於是,1/(1-x)^2=1+2x+3x^2+4x^3+5x^4+....。一步就得到了我們所需要的東西!不斷地再求導數,我們同樣可以得到剛才用復雜的牛頓二項式定理得到的那個結論(自己試試吧)。生成函數還有很多其它的處理手段,比如等式兩邊同時乘以、除以常數(相當於等式右邊每一項乘以、除以常數),等式兩邊同時乘以、除以一個x(相當於等式右邊的系數“移一位”),以及求微分積分等。神奇的生成函數啊。
    我們用兩種方法得到了這樣一個公式:1/(1-x)^n=1+C(n,1)x^1+C(n+1,2)x^2+C(n+2,3)x^3+...+C(n+k-1,k)x^k+...。這個公式非常有用,是把一個生成函數還原為數列的武器。而且還是核武器。


    接下來我們要演示如何使用生成函數求出Fibonacci數列的通項公式。
    Fibonacci數列是這樣一個遞推數列:f(n)=f(n-1)+f(n-2)。現在我們需要求出它的生成函數g(x)。g(x)應該是一個這樣的函數:
    g(x)=x+x^2+2x^3+3x^4+5x^5+8x^6+13x^7+...
    等式兩邊同時乘以x,我們得到:
    x*g(x)=x^2+x^3+2x^4+3x^5+5x^6+8x^7+...
    就像我們前面說過的一樣,這相當於等式右邊的所有系數向右移動了一位。
    現在我們把前面的式子和后面的式子相加,我們得到:
    g(x)+x*g(x)=x+2x^2+3x^3+5x^4+8x^5+...
    把這最后一個式子和第一個式子好好對比一下。如果第一個式子的系數往左邊移動一位,然后把多余的“1”去掉,就變成了最后一個式子了。由於遞推函數的性質,我們神奇地得到了:g(x)+x*g(x)=g(x)/x-1。也就是說,g(x)*x^2+g(x)*x-g(x)=-x。把左邊的g(x)提出來,我們有:g(x)(x^2+x-1)=-x。於是,我們得到了g(x)=x/(1-x-x^2)。
    現在的任務是要把x/(1-x-x^2)還原成通項公式。這不是我們剛才的1/(1-x)^n的形式,我們要把它變成這種形式。我們發現,1-x-x^2=[1-(1-√5)x/2]*[1-(1+√5)x/2] ((1-√5)/2和(1+√5)/2是怎么算出來的?顯然它們應該是x^2-x-1=0的兩個根)。那么x/(1-x-x^2)一定能表示成?/[1-(1-√5)x/2]+?/[1-(1+√5)x/2]的形式(再次抱歉,輸入數學公式很麻煩,將就看吧)。這是一定可以的,因為適當的?的取值可以讓兩個分式通分以后分子加起來恰好為一個x。?取值應該是多少呢?假設前面一個?是c1,后面那個是c2,那么通分以后分子為c1*[1-(1+√5)x/2]+c2*[1-(1-√5)x/2],它恰好等於x。我們得到這樣兩個式子:常數項c1+c2=0,以及一次項-c1*(1+√5)/2-c2*(1-√5)/2=1。這兩個式子足夠我們解出c1和c2的准確值。你就不用解了,我用的Mathematica 5.0。解出來c1=-1/√5,c2=1/√5。你不信的話你去解吧。現在,我們把x/(1-x-x^2)變成了-(1/√5)/[1-(1-√5)x/2] + (1/√5)/[1-(1+√5)x/2]。我們已經知道了1/[1-(1-√5)x/2]的背后是以(1-√5)/2為公比的等比數列,1/[1-(1+√5)x/2]所表示的數列公比為(1+√5)/2。那么,各乘以一個常數,再相加,我們就得到了Fibonacci數列的通項公式:f(n)=-(1/√5)*[(1-√5)/2]^n + (1/√5)*[(1+√5)/2]^n。或許你會問,這么復雜的式子啊,還有根號,Fibonacci數列不都是整數嗎?神奇的是,這個充滿根號的式子對於任何一個自然數n得到的都是整數。熟悉用特征方程解線性遞推方程的同學應該知道,以上過程實質上和找特征根求解沒有區別。事實上,用上面所說的方法,我們可以求出任何一個線性齊次遞推方程的通項公式。什么叫做線性齊次遞推呢?就是這樣的遞推方程:f(n)等於多少個f(n-1)加上多少個f(n-2)加上多少個f(n-3)等等。Fibonacci數列的遞推關系就是線性齊次遞推關系。

    我們最后看一個例子。我們介紹硬幣兌換問題:我有1分、2分和5分面值的硬幣。請問湊出n分錢有多少種方法。想一下剛才的水果,我們不難得到這個問題的生成函數:g(x)=(1+x+x^2+x^3+...)(1+x^2+x^4+...)(1+x^5+x^10+..)=1/[(1-x)(1-x^2)(1-x^5)]。現在,我們需要把它變成通項公式。我們的步驟同剛才的步驟完全相同。我們把(1-x)(1-x^2)(1-x^5)展開,得到1-x-x^2+x^3-x^5+x^6+x^7-x^8。我們求出-1+x+x^2-x^3+x^5-x^6-x^7+x^8=0的解,得到了以下8個解:-1,1,1,1,-(-1)^(1/5),(-1)^(2/5),-(-1)^(3/5),(-1)^(4/5)。這個不是我解出來的,我還是用的Mathematica 5.0。不是我不想解,而是我根本不會解這個8次方程。這也是為什么信息學會涉及這些東西的原因:次數稍微一高,只好交給計算機解決了。於是,(1-x)(1-x^2)(1-x^5)=(1+x)(1-x)^3(1+(-1)^(1/5) x)()()() (省略不寫了)。注意那個(1-x)^3。由於等根的出現,我們不得不把(1-x)^3所包含的(1-x)和(1-x)^2因子寫進一會兒的分母里,不然會導致解不出合適的c來。你可以看到很多虛數。不過沒關系,這些虛數同樣參與運算,就像剛才的根式一樣不會影響到最后結果的有理性。然后,我們像剛才一樣求出常數滿足1/(1-x)(1-x^2)(1-x^5)=c1/()+c2/(1-x)+c3/(1-x)^2+c4/(1-x)^3...+c8/()。這個解太復雜了,我用Mathematica解了幾分鍾,打印出了起碼幾十KB的式子。雖然復雜,但我確實是得到了通項公式。你有興趣的話可以嘗試用Mathematica解決一下1/[(1-x)(1-x^3)] (只有1分和3分的硬幣)。解c的值時可以用SolveAlways[]函數。你可以親眼見到,一個四五行的充滿虛數的式子最后總是得到正確的整數答案。

    生成函數還有很多東西,推導Catalan數列啊,指數生成函數啊,之類的。我有空再說吧,已經5000多個字了。

    huyichen一直在問那道題。很顯然,那道題目和上面的兌換硬幣有些聯系。事實上,很多與它類似的題目都和生成函數有關。但那個題卻沒有什么可以利用生成函數的地方(或許我沒想到吧)。或許每個max的值有什么方法用生成函數解出來,但整個題目是不大可能用生成函數解決的。
    近來有個帖子問一道“DP天牛”題目的。那個題目也是這樣,很多與它類似的題目都和DP有關,但那道題卻不大可能動規。我總覺得它可以歸約到裝箱問題(考慮體積關系,最少要幾個箱子才能把物品放完),而后者貌似屬於NPC。或許我錯了吧,現在沒事就在研究理論的東西,很久沒有想過OI題了,這方面的能力已經開始退化了。

Matrix67原創
做人要厚道,轉貼請注明出處


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com