註:由於輸入公式困難,本篇用 C(n,k)表示組合,n選k;P(n,k)表示排列,n選k;∑k=a~b 表示求和。5.1 僱傭問題
假設你要僱傭一個新的辦公室助理,僱傭代理每天想你推薦一個應聘者(連續推薦n個),你面試這個人,如果這個應聘者比目前的辦公室助理更優秀,你就會辭掉當前的辦公室助理,然後聘用這個新的。面試一個人需付給僱傭代理一筆費用,聘用辦公助理也需要費用。
假設面試費用為Ci,僱傭的費用為Ch,假設整個過程中僱傭了m次,於是總的費用是 nCi+mCh。由於n是固定值,總費用的變化取決於m值。
這個情境用來當做一般計算範式的模型,通常情況下我們需要檢查隊列中的每個成員,並且維護一個目前的獲勝者,來找出序列中的最大或最小值。僱傭問題是對哪一個成員當前獲勝的更新頻繁程度建立模型。
最壞情況
最壞情況下,我們僱傭了每一個應聘者,m=n。
機率分析
事實上,我們既不能得知應聘者出現的順序,也不能控制這個順序,因此我們使用機率分析。機率分析就是在問題的分析中使用機率技術。為了使用機率分析,必須使用關於輸入分布的知識或者對其做假設,然後分析演算法,計算出一個期望的已耗用時間。這個期望值通過對所有可能的輸入分布算出。
有些問題,我們對所有可能的輸入集合做某種假設。對於其他問題,可能無法描述一個合理的輸入分布,此時就不能使用機率分析方法。
在僱傭問題中,可以假設應聘者是以隨機順序出現的。假設可以對任何兩個應聘者進行比較並確定哪個更優;換言之,在所有的應聘者之間存在這一個全序關係。因此可以使用從1到n的唯一號碼來標誌應聘者的優秀程度。用rank(i)來表示應聘者i的名次。這個有序序列<rank(1),rank(2),..., rank(n)>是序列<1,2,...,n>的一個排列。說應聘者以隨機的順序出現,就等於說這個排名列表是1到n的n!中排列中的任何一個,每種都以相等的機率出現。
隨機演算法
在許多情況下,我們對輸入分布知識知之甚少;即使知道關於輸入分布的某些資訊,也無法對這種分布建立模型。然而通過使一個演算法中的某些部分的行為隨機化,就常常可以利用機率和隨機性作為演算法設計和分析的工具。
比如在僱傭問題中,如果僱傭代理給我們一份應聘者的名單,每天我們隨機地挑選一個應聘者進行面試,從而確保了應聘序列的隨機性。
更一般地,如果一個演算法的行為不只有輸入決定,同時也由隨機數產生器所產生的數值決定,則稱這個演算法是隨機的。
練習5.1.2
假設Random(a,b)以相同機率返回a到b之間的任何一個數字,描述Random(a,b)過程的一種實現,它只調用現有實現Random(0,1)。作為a和b的函數,你的程式的期望已耗用時間是多少?假設Ramdom(0,1)的已耗用時間是常數。
解法1:
分析:假設k=b-a+1。那麼Random(a,b)的本質就是從k個數字中隨機等機率地選出一個,不妨用Random(k)來表示。 假設這樣來進行一輪操作,利用Random(0,1)產生長度為k個0,1序列S = (R1,R2,...,Rk)。如果R1=R2=...=Rk,這一輪操作就作廢了,重新進行;否則如果Ri=0就將第i個數淘汰,問題就轉化了為對少於K個數的隨機播放。這裡不妨假設對於m<k,演算法Random(m)已經實現。
Ai ->事件第i個數最終被選中
Bim ->事件第i個數和其他m-1個數在這一輪篩選中被保留
Cim ->事件第i個數在這m個保留下來的子集中最終被選中
Pr{Ai/Bim} = Random(m) = 1/m;
Pr{Ai,Bim} = Pr{Bim}*1/m;
Pr{Ai} = ∑m=1~k-1Pr{Ai,Bim} = Pr{Ai} = ∑Pr{Bim}*1/m;
Pr{Bim} = C(k-1,m-1)(1/(2n-2)), 由於我們忽略了s為全1全0兩種序列,所以其他序列的機率是1/(2n-2)
求解後可得 Pr{Ai} = 1/k。
由於Random(2)是現成的,於是通過數學歸納法可知Random(k)通過上述演算法都可以求解。
演算法Random(k)的期望已耗用時間:只要不是出現s為全0全1這兩種狀況,演算法規模就可以縮小。這兩種狀況的機率為 2/2k。依據伯努利實驗的結論期望進行 Sk = 1/(1-2/2k)輪篩選就可以縮小問題規模。
T(k) = 篩選輪次*k*T(2) + T(i) ; i 以一定的機率分佈於:1~k-1。
設常量 C = T(2)
E[T(k)] =Sk*k*C + E[T(1)]*C(k,1)(1/(2k-2)) +...+E[T(k-1)]*c(k,k-1)(1/(2k次-2))
這個遞推式解不了。
簡化演算法
上面的演算法給出了比較嚴格的推理過程,但演算法過程可以簡化:如果k為偶數,則將S均分成兩組,通過一次R(0,1)來淘汰其中一組;如果S為奇數,則用上述方法來分組,將佔多數的一組淘汰。可以證明這個演算法後也是正確的。只要在某一輪的測試中R(0,1)的輸出為全0或全1,問題的規模就可以縮小一半。這樣演算法的期望已耗用時間遞推式可以表示為 E[T(k)] <= Sk*k*C + E[T(k/2)], 應該為Θ(k)。
解法2:
假設m=2k次,那麼Random(m)可以很容易有Random(k)獲得。假設這個m>k&&m<2k,那麼可意由這種方式來設計Random(K):
Random(K)
value = Random(m)
if (value<=k)
return value
else
return Random(K)
演算法本質上也是一個伯努力實驗。
也可以取m大一些,比如m>Nk:
Random(K)
value = Random(m)
if (value<=Nk)
return value/N
else
return Random(K)
練習5.1.3
假設你希望以各1/2的機率輸出0和1。你可以自由使用一個輸出0或1的過程BIASED-RANDOM。它以機率p輸出1,以機率1-p輸出0,其中0<p<1,但是你並不知道p的值。給出一個利用BIASED-RANDOM作為子程式的演算法,返回一個無偏向的結果。你的演算法的期望已耗用時間是多少?
分析:設計的思路是利用對稱性。 假設有兩個基於BIASED-RANDOM的伯努利實驗序列A、B。每個實驗序列都會產生0,1值序列;每一輪A和B各進行一次,如果該輪實驗的結果是ai>bi(即ai=1,bi=0)則演算法結束,結果為1;如果ai<bi則演算法結束結果為0;如果ai=bi則開始下一輪迭代。
由於每一輪實驗都是獨立的,所以只要能夠證明每一輪在得出結果的條件下,得出1和得出0的機率相等就可以了。
事件 Mi : 第i輪實驗得出了結果,即ai!=bi;
事件 Ai :結果為1;
事件 Bi :結果為0;
Pr{Ai/Mi} = Pr{Ai,Mi}/Pr{Mi};
Pr{Ai,Mi} = Pr{ai=1,bi=0} = p*q;
Pr{Bi,Mi} = Pr{ai=0,bi=1} = q*p;
因此有Pr{Ai/Mi} = Pr{Bi/Mi}
該演算法的執行時間取決於進行多少輪實驗後達到ai!=bi。 對任意i,Pr{ai=bi} = pp+qq Pr{ai!=bi}= 2pq。這又是一個伯努利實驗。期望實驗次數E[n] = 1/2pq。
5.2指標隨機變數
定義:
為了分析包括包括僱傭分析在內的許多演算法,我們將使用指標隨機變數,它為機率和期望之間的轉換提供了一個便利的方法,給定一個樣本空間S和時間A,那麼事件A對應的指標隨機變數
1 如果A發生
Xa = 0 如果A沒有發生
E[Xa] = Pr{A}
利用指標隨機變數分析僱傭問題:
假設應聘者以隨機的順序出現,令X作為一個隨機變數,其值等於僱傭一個新的辦公室次數。那麼 E[X] = ∑xPr{X=x},但這一計算會很麻煩。
我們定義n個和每個應聘者是否被僱傭對應的變數,Xi為對應於第i個應聘者被僱傭這個事件的指標隨機變數。有X=X1+X2+...+Xn。
E[Xi] = Pr{Xi} = 1/i,因為應聘者是隨機出現的,所以第i個應聘者比前面i-1個優秀的機率是1/i。
因此E[X] = 1+1/2+1/3+...+1/n。
練習5.2.2:
在僱傭問題中,假設應聘者以隨機的順序出現,正好僱傭兩次的機率是多少?
分析:第一個應聘者肯定被僱傭,最優秀的應聘者也肯定被僱傭。如果第一個就是最優秀的那麼指揮僱傭一次,這種情況就可以排除。那麼恰好僱傭兩次就意味這在第一個應聘者和最優秀的應聘者之間的應聘者都不如第一個優秀。由於應聘者是隨機出現的,那麼任何一種序列都是等可能的,只要能求出滿足前一要求的排列數目就能求出機率。
假設應聘者對應於集合S={1,2,3,...,n}。應聘者的優秀程度就有數值來標記。假設我們將最大的數n暫時抽出。將剩下的1~n-1個分成兩組,在由這兩組形成兩個序列S1、S2,要求S1的第一個數是S1中最大的數,S2完全隨機排列, 那麼 序列 S1nS2 就是滿足需求的一種n排列。反過來,每種滿足需求的排列都可以表示成這種形式。
這種排列的數目有m = ∑k=1~n-1C(n-1,k)(k-1)!*(n-1-k)! --k=1~n-1
機率為: m/n! = 1/n∑k=1~n-11/k
練習5.2.4:
帽子保管問題:有n位顧客,他們每人給餐廳負責保管帽子的服務生一頂帽子,服務生以隨機的順序將帽子歸還給顧客,請問拿到自己帽子的客戶的期望數目是多少?
分析:設指標隨機變數Xi對應於事件“顧客i拿到自己的帽子”, 可知 E[Xi]= 1/n。於是拿到自己帽子客戶的期望數目是 ∑E[Xi] = 1。
練習5.2.5:
假設A[1...n]是由n個不同數構成的數組,如果i<j且A[i]>A[j],則稱(i,j)對位A的逆序對。假設A中元素形成<1,2,...,n>上的一個均勻隨機排列,利用指標隨機變數來計算A中逆序對的期望。
分析:設指標隨機變數Xij對應於事件“A[i]>[Aj]”, 那麼 E[Xij]= 1/2。於是逆序對的期望數目為∑1=<i<j<=nE[Xij] = n(n-1)/4。
5.3隨機演算法
在僱傭問題中,如果應聘者是以隨機順序出現的話,僱傭一個新的辦公室助理的期望次數是lnn。這個演算法是隨著輸入的變化而變化的。對於某個特定的輸入,它總是會產生固定的僱傭次數。這樣就存在昂貴的輸入,不貴的輸入和適中的輸入。如果先對應聘者進行隨機排列,此時隨機發生在演算法上而不是發生在輸入分布上。每次運行這個演算法,執行依賴於隨機的選擇,而不是依賴於輸入。這就是隨機演算法和機率分析的區別。
隨機排列數組
許多隨機演算法通過排列給定的輸入數組來使輸入隨機化。這裡討論兩個隨機化方法,假設給定一個數組A,它包含元素1到n。我們的目標是構造這個數組的一個隨機排列。
Permute-By-Sorting
一個常用的方法是為數組A[i]賦一個隨機的優先順序P[i],然後根據優先順序對數組中的元素進行排序。這個過程稱為Permute-By-Sorting。
Permute-By-Sorting
1 n <- length[A]
2 for i<- 1 to n
3 do P[i]=RANDOM(1,n3)
4 Sort A, using P as keys
5 return A
第三行在範圍1~n3之間選取隨機值,是為了讓p中的所有優先順序儘可能唯一。
現證明:如果所有的優先順序是唯一的,那麼Permute-By-Sorting可以產生輸入的均勻隨機排列。
對Ai產生第ki大的優先順序,那麼k1,k2,...,kn是1~n的一個排列,該排列決定了最終的A排列。證明K1K2...Kn是1~n一個均勻隨機排列即可。假設某個1~n的均勻隨機排列s1...Sn,假設分別以Xi代表事件Ki等於Si。
於是 Pr{X1∩X2∩...∩Xn} = Pr{X1}*Pr{X2|X1}*Pr{X3|X2∩X1}...{Pr{Xn|Xn-1∩Xn-2∩...∩X1} = 1/n!
應為Pr{X1} = 1/n; Pr{X2|X1} = 1/n-1;...
Permute-In-Place
一個更好的方法是原地排列給定的數列。
Permute-In-Place
1 n <- length[A]
2 for i <- 1 to n
3 do swap A[i]<-->A[Random(i,n)]
使用迴圈不變式來證明。證明第i次迭代後,產生的是A的一個均勻隨機i排列。
初始:第一次迭代之前,條件滿足。
保持:假設第i次迭代產生了排列 X1X2...Xi,只要證明對任意特定值x1,x2,...xi∈A, Pr{X1=x1∩X2=x2∩...∩Xi=xi}的機率相等。 Pr{X1=x1∩X2=x2∩...∩Xi=xi} = Pr{Xi=xi | X1=x1∩X2=x2∩...∩Xi-1=xi-1}*Pr{X1=x1∩X2=x2∩...∩Xi-1=xi-1} = 1/n-i+1 * Pr{X1=x1∩X2=x2∩...∩Xi-1=xi-1}。由於已知排列X1X2...Xi-1是一個均勻隨機i-1排列。所以得證。
其實依次類推可知Pr{X1=x1∩X2=x2∩...∩Xi=xi}= 1/n*1/n-1*...1/n-i+1 = (n-i)!/n!。
終止:可知任意排列的機率為 1/n!。
練習5.3.3
假設修改Permute-In-Place演算法,不是將元素A[i]與A[i...n]中的隨機一個元素進行交換,而是將它與數組任何位置上的隨機元素相交換:
Permute-With-All
1 n <- length[A]
2 for i <- 1 to n
3 do swap A[i]<-->A[Random(1,n)]
這段代碼會產生均勻隨機排列嗎?
分析:這問題沒有找到嚴謹的證明方法,不過有一個投機的證明方法:每一步交換的方法有n中,那麼依據乘法原理整個過程的交換序列有n的n次種,每一種交換序列產生唯一的一個最終元素序列。元素序列有n!種。由於n的n次並不能被n!整除,所以不可能等機率地產生元素序列。
練習5.3.4
證明程式PERMUTE-BY-SORTING的數組P中,所有元素都唯一的機率至少是1-1/n。
分析:假設Random(1,n3)產生的n個數值為a1,a2,...,an;事件Xi表示a1~ai互不相等。Xn = {an不等於a1...an-1之一} ∩ Xn-1,於是 Pr{Xn} = Pr{an不等於a1...an-1之一 | Xn-1} *Pr{Xn-1} = (n3-n+1/n3)*Pr{Xn-1}。
遞推得 Pr{Xn} = ∏k=1~n(n3-k+1)/n3 > (1-1/n2)n > C(n,0)*1 - C(n,1)(-1/n2) = 1-1/n。
練習5.3.6
解釋如何?演算法Permute-By-Sorting,來處理兩個或更多優先順序相同的情況。亦即即使有多個優先順序相同,演算法也必須產生一個均勻隨機序列。
分析:對幾個優先順序相同的項,再進行一輪隨機優先順序排序;如果再有相同,再進行一次...。思想就是要確保這幾個優先順序相同的項得到隨機的排列。
5.4機率分析和指標隨機變數的進一步使用
5.4.1 生日悖論
一個房間裡面的人數要達到多少,才能使有至少兩個人生日相同的機率達到1/2。
分析1:
假設一年的天數為Y天,對房間裡的所有人進行編號 m1,m2,...,mn。假設事件 Ai = mi與m1~mi-1的生日不同, 事件Bi=m1~mi生日互不相同;
於是 Bk = ∩Ai [i=1~k],
Pr{Bk} = Pr{Bk-1∩Ak} = Pr{Bk-1}*Pr{Ak|Bk-1} =Pr{Bk-1}*(Y-k+1)/Y。
依據遞推式 Pr{Bn} = ∏(1-(i-1)/Y) {i=1~n} 求使Pr{Bn} < 1/2的最小n值。
分析2:利用指標隨機變數
令指標變數 Xij 對應於事件 {人i和人j生日相同}
E[Xij] = 1/Y;
∑E[Xij] = 1/Y * k(k-1)/2;
隨機變數 X = ∑Xij 表示生日相同的兩人對的對數;
如果取Y=356天,則只要k>=28,就可以期望至少有兩個人生日。
注意:依據期望來反推機率只是簡單而近似的分析,並不如分析1準確。不過雖然兩種分析方法的結果不一致,但是都是Θ(n1/2)。