【演算法】3 由招聘問題看隨機演算法

nomasp發表於2015-05-29

招聘問題

我想看我部落格的還是學生人群偏多吧,本身很快就要去面試了,在這篇部落格的問題中,我們就把自己當作Boss過把癮。

某天,你想僱用一名演算法工程師。當然,不可能讓你這個Boss親自去到處練習應聘者,而是選擇了中介。僱用中介每天都會給你推薦一個應聘者(PS:還是讓自己輕鬆點,一天只應聘一個人哈)。是個地球人都知道,你必須要給中介付一小筆錢。然後如果你僱用了一個應聘者則需要更多的錢,一來你要解僱現有的演算法工程師,更重要的是你要付給中介一大筆錢。在這個問題中還有一個關鍵的問題,雖然有些不合情理——只要遇到更好的演算法工程師,你都會把之前的給解僱掉(忽略合同等等哦)。

相信大家一看這個問題就知道重點是什麼了,錢,錢,錢,還是錢。你希望費用是最低的。

那麼解決這個問題的邏輯呢,當然就是:

1)從1到n個應聘者中不斷地面試
2)如果當前應聘者比上一個更好,則僱用當前應聘者並解僱上一個僱用者

問題是如何將實際問題轉換成虛擬碼,虛擬碼才是最重要的,有了它你便可以將其改成任何語言的描述。

HIRE-ALGORITHM-ENGINEER(n)
1   employee=0
2   for i=1 to n
3       interview candidate i
4       if candidate i is better than employee 
5           employee = i
6           hire candidate i

相比大家都看過該系列的前兩篇演算法博文呢吧?這一篇和前面兩篇的區別在於問題的角度不同了,以前我們考慮執行時間,現在我們考慮僱用所花的費用。

大家想想這和前面用到的歸併排序有哪些相似點呢?

不管是執行時間,還是花費費用,在演算法之中都是由一些操作來執行的,所以終究還是逃離不了演算法的分析。

如前所述,假定總共有n個人需要面試,有m個人最終被僱用。面試一個應聘者時需要給中介的費用是小的,設為cs

c_s
;而在你面試通過了這個應聘者後給中介的費用才是大的,設為cb
c_b

所以這個演算法總共要花費的費用為O(csn+cbm)

O(c_sn+c_bm)
。大家應該有很清晰的理解這個問題吧?為什麼最終由m個人被僱用而不是1個人被僱用呢。原因是這樣的:比如說你現在面試了一個應聘者,你覺得他蠻優秀的,但是在10天你又遇到了一個更加優秀的,於是你便辭退了先前的僱員,聘請了最新看中的應聘者。

所以說,無論如何我們都會面試n個人,總費用csn

c_sn
也是固定的,真正對演算法有著深遠(波動)影響的應該是這僱用的m個人。

這個是時候,我們就按情況的不同作具體分析了。

很顯然,如果這些應聘者按優秀程度(僅僅是舉個例子)來遞增順序進行面試,最優秀的最先面試,那麼你在應聘這個方面所花費的價錢就僅僅是cs1

c_s*1
了。

相反,如果是按照遞減順序進行面試,那優秀的最後面試,那麼這下麻煩可大了,你所花費的價錢就是csn

c_s*n
,如果n特別大那就更加糟糕了。

這個例子也許不夠讓大家印象深刻,那就再來一個例子。就比如說學校、公司、電視臺等的各種晚會,為了更加吸引觀眾更多的關注當然要最好的節目留在最後了,這也是傳說中的壓軸。如果最後的節目一開始就結束了,後面的節目也許就沒多人人想看了,這個問題就是前面的僱用問題有著相同的思想,當然了,情況是相反的。說到壓軸,也許舉高考的例子更加合適吧?如果把壓軸題放在一開始,或者隨意放置……那豈不是一片混亂?為了考生考慮都統一把壓軸題放到了最後。

如果大家理解了上面的描述,那就相當於理解了最壞情況分析

在這個演算法中,我們顯然不可能每次都去強制控制它的輸入,因此便有了隨機演算法這麼一說。

所謂的隨機演算法,就是使用排列的順序隨意。選取一個主元,輸入的順序便不重要了。無論所提供的輸入是遞增排序還是遞減排序,亦或是沒有排序,都對演算法沒有影響,因為輸入是什麼根本就不重要了。我們都會將其打亂,讓它們隨機分佈。

既然選擇了這個演算法,自然有它的優點:

1)它的執行時間不依賴於輸入序列的順序
2)無需對輸入序列的釋出做任何假設
3)無論是怎樣的輸入都不會引發最差的執行情況
4)而最差的情況卻是由隨機數產生器決定的

那麼什麼樣的演算法是隨機的呢?

其行為不僅由輸入決定,而且也有隨機數生成器產生的數值決定,這種演算法就是隨機的。

話說回來什麼叫做隨機數生成器呢?

隨機數生成器RANDOM,通過呼叫RANDOM(a,b)而返回a到b之間的整數且每個整數都以等概率出現。

然而許多程式設計環境/語言都會提供一個偽隨機數生成器(比如說C#裡面的Random),它其實是一個確定性演算法,只不過其結果在統計上看上去是隨機的。

在分析隨機演算法時,和前面的就有區別了。我們開始以執行時間的期望值來衡量,而輸入值也通過隨機數來生成。所以隨機演算法的執行時間也叫做期望執行時間,因為這一切都是不確定的,所以我們只能期望,期望,期望。

如果一個演算法的輸入是概率分佈的,那麼就分析其平均情況執行時間;當演算法本身對於輸入可以通過隨機過程來選擇,那麼就分析其期望執行時間。

隨機演算法

我們不是假設輸入的一個分佈,而是設定一個釋出。也就是說在這個演算法開始前,先隨機化它的輸入,讓這些輸入擁有等可能的出現概率。

每次執行這個演算法時,執行都依賴於隨機選擇,所以執行很和前面的不同。因此變有了前面”無論是怎樣的輸入都不會引發最差的執行情況“的優點。

所以對於前面的虛擬碼唯一需要改變的只是增加”隨機化應聘者序列“這一段。

RANDOMIZED-HIRE-ALGORITHM-ENGINEER(n)
1   randomly permute the list of candidates
2   employee=0
3   for i=1 to n
4       interview candidate i
5       if candidate i is better than employee 
6           employee = i
7           hire candidate i

那麼問題來了,虛擬碼中的第1行該如何實現呢?還記得鍵值對麼,這是我一開始覺得比較牛叉的概念,後來發現也不過如此。這裡我們就可以用到這個理念。

我們給陣列中的每個元素賦一個優先順序,優先順序和陣列中的元素都是數字。以往我們給陣列中的元素排序都是直接按元素的大小進行比較、排序的,這裡則跑開了元素本身,通過元素對應的優先順序來比較,優先順序優先的數即更小,我們也可以將其排在後面。

Sort-By-Priority(A)
1   n=A.length
2   let P[1...n] be a new random array
3   for i=1 to n
4       P[i]=RAMDOM(1,n^2)
5   sort A, using P as sort keys

這裡我們將優先順序是範圍設為了1到n2

n^2
,其實只是為了擴大它的範圍以不至於優先順序重疊,你當然也可以設定為n的三次方,或是4次方。



感謝您的訪問,希望對您有所幫助。 歡迎大家關注、收藏以及評論。


為使本文得到斧正和提問,轉載請註明出處:
http://blog.csdn.net/nomasp


相關文章