現在有一個問題:
我們想得到一個復雜運算的通式。
所謂通式就是類似 result = F(x) 的形式,只要我們給出輸入 x,就可以利用通式得出計算結果。
有人會問這不是很簡單嗎?我們不就是這樣解決問題的嗎?
其實大多數情況下,我們可以這樣解決問題。因為我們沒有遇到復雜的問題,所以沒有想過對應的解決辦法。現在給出一個例子:
錯排問題:
某網站收集了n個用戶的個人信息。每個人手里有一張優惠券,現在網站搞混合抽獎,兩兩交換優惠券信息。最終每個人都獲得了一張新的優惠券!
其實就是一個優惠券換優惠券的活動。
問題是:一共有多少種分配方案?
可以看到這道題有幾個要點:
1、每個人獲得的新優惠券不能還是原來自己的。
2、每個人都與其他人進行了交換,但多少次不管。且優惠券無重復。
我們沒辦法一下子寫出通式來,即給我一個用戶數量n,我就可以告訴你有幾種分配方案。
而只能寫出類似 An = A(n-1)+A(n+2)的遞推表達式。(當然不是這個,這是斐波那契遞推關系式)
那有人問,我就利用遞推公式求出來不就好了嗎?但你知道在計算機里遞推用到的是“棧”,資源開銷很大,在不知道復雜度的情況下,容易造成事故。
而如果我們用簡單的加減乘除就能解決這個運算問題是不是節省了很多內存資源呢?
好戲就要上演了。
步驟:
1、換一種思想,既然用到遞推,我們就設Dn代表n個用戶有Dn個解決方案。
Dn就是我們最終要求的數。
2、類似的,D(n-1)代表n-1個用戶的方案數。
我們不知道D(n-1)到底是多少,但是我們可以利用它。
①現在假定n-1個用戶對應的方案數D(n-1)我們已經求出來了。
那第n個用戶來了,他也要參加抽獎。我們想一想他跟誰交換優惠券呢?
對了,和任何人都行!因為n-1個人已經錯排好了,而n現在和他們任何人交換,n拿的都不是自己的;拿到n手中優惠券的人也拿的不是自己的。所以這n個人就錯排好了。
(結果:D(n-1)*(n-1)) ? ? ? ? ? ?(前一個(n-1)是下標,別搞混了。)
有人說這不是忽悠我嗎?n-1個人的方案數還沒告訴我呢。
先接著往下看。
②假設n個人都沒交換呢,現在先讓第n個人(對這個人比較特殊,他先交換)和n-1里的任意一個人交換。好了,我們就先不動他倆了。剩下還有n-2個人等待被交換,不管,先記做D(n-2)。這n個人也都被交換好了。
(結果:(n-1)*D(n-2) ? ? )
綜合①、②得出 ?n個人的交換方案:
D(n) = (n-1)*D(n-1) + (n-1)*D(n-2) ? ?兩個結果相加就得到了。
會有人疑惑這兩種情況涵蓋所有了嗎?
我們來想一想,這其實是把問題分成了兩類:
第n個人要么是在其他人交換完之后再交換,要么先交換。這兩種情況都保證了第n個人得到了原不屬于自己的優惠券。
那同理,第n-1個人也是這么分的……第1個人也是這么分的(只不過其他人數是0而已,共交換0次哈哈)
所以我們得到的遞推公式是正確的!
D(n) = (n-1)*D(n-1) + (n-1)*D(n-2) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ①
3、下面跟著我的步驟一步步化簡。
式①可以寫成:
D(n) ?- nD(n-1) = - [ D(n-1) - (n-1)*D(n-2) ]
=……
= (-1)^(n-1) * (D1 - D0)
更清楚的推導看下圖:
經過一番推導,我們得出了“給定用戶數n,求交換方案數Dn”的通式!
雖然結果比較復雜(大多數是這樣),但其中原理著實讓人著迷。
結語:
其實并不是所有的遞推關系都能得到一個通式:對于“線性常系數齊次遞推關系”可以百分百求出其通式,就像斐波那契數一樣;而對于“線性常系數非齊次遞推關系”要看具體情況。
感興趣的可以去wiki查這些關鍵詞,或者看清華大學的視頻教程。
地址在這:http://pan.baidu.com/s/1bpj4PMB