貪心演算法的乙個出人意料的應用

2021-05-12 11:16:18 字數 1729 閱讀 5220

ibm ponder this上個月的題目比較有趣:我在心裡面想乙個2到166之間的整數(包括2和166),你的任務是用盡可能少的是非問句(我只能回答是或者否)猜出這個數除1以外的最小約數是多少。

(1) 尋找一種策略使得在最壞情況下猜到答案的詢問次數最少。

(2) 尋找一種策略使得在平均情況下猜到答案的期望詢問次數最少。

第乙個問題很容易回答。雖然2到166之間的整數一共有165個,但它們的最小約數(以後我們說的「最小約數」都是指的不包括1的最小約數)只有38種。因此,事實上你只需要用二分法在38個可能的答案當中找出乙個就可以了。由於2^5=32,2^6=64,因此最壞情況下需要6次詢問才能保證猜到。

真正困難的是後面乙個問題:要想讓平均猜測次數盡可能少,我們該從**入手呢?

為了方便思考,不妨讓我們把這個問題簡化一下。假設題目條件中我心裡想的數字範圍是2到10之間的自然數,由於這些數的最小約數分別是2、3、2、5、2、7、2、3、2,只有四種情況,因此只需要兩個問題即可問出答案——比方說,第一次問「最小約數是2或3嗎」,回答「是」則再問「最小約數是2嗎」,回答「否」則問「最小約數是5嗎」,即可保證知道答案。若採用這種策略的話,不管我心裡想的是什麼數,你總是需要恰好兩次猜測才能猜出答案。但事實上,由於最小約數是2的可能性遠遠大於其它的數,因此減少最小約數是2時的猜測次數,增加最小約數是5和7時的猜測次數,雖然最壞情況下需要的猜測次數變多了,但我們或許能得到更優的平均猜測次數。我們可以這樣做:先問「最小約數是2嗎」。如果回答是,則直接猜到,因此當我心裡想的數是2、4、6、8、10中的乙個時,猜測次數僅為一次。如果回答否,則問題變為了下述子問題:當我心裡所想的數為3、5、7、9時,平均需要多少次猜測才能猜出它的最小約數?對於這個子問題,我們同樣發現,由於最小約數為3的概率較大,因此直接問「最小約數是3嗎」更好。採取這種策略,我們可以看到:當我心裡想的數是2、4、6、8、10中的乙個時,只需要一次猜測;當我心裡想的數是3或者9時,需要兩次猜測;當我心裡想的數是5或者7時,一共需要三次猜測。因此,採用這種策略平均需要(5*1 + 2*2 + 1*3 + 1*3)/9 = 15/9 ≈ 1.67次猜測。

覺得上面的圖是不是很熟悉?當你把上圖從下面倒著往回推時,你會發現這是乙個經典的貪心演算法問題。我們把擁有相同最小約數的數放進乙個集合,則得到的四個集合分別為、、、。把兩個集合合併成乙個大集合,直觀意義就是這兩個集合是由乙個大集合通過一次詢問劃分出來的,此時總的詢問次數就增加了兩個集合總的元素個數那麼多。借用類似於huffman編碼的演算法,我們立即想到,不斷合併當前元素個數最少的集合,得到的總猜測次數就應該是最優的。利用mathematica求解原問題,我們可以得出,對於2到166的情況,平均494/165=2.9939...≈3次詢問就能找到那個最小約數。

當你聯想到了huffman編碼時,你會驚奇地發現,原問題完全等價於huffman編碼問題。注意到「猜到最小約數」的意思就是說,每乙個可能的答案都對應著乙個yes/no序列(也就是乙個01串),且任一串行都不能成為另乙個序列的字首。而這些最小約數的頻次是不同的,因此我們需要給所有可能的最小約數進行二進位制編碼,使得它們的加權長度最短。這就是乙個典型的huffman編碼問題了。

推薦 貪心演算法的乙個出人意料的應用

這篇文章是在matrix67大牛部落格上挖的,這個問題囊括了二分查詢和貪心演算法 huffman法 兩種查詢最優問題的演算法.十分值得推薦.貪心演算法的強大,領略無遺.ibm ponder this上個月的題目比較有趣 我在心裡面想乙個2到166之間的整數 包括2和166 你的任務是用盡可能少的是非...

貪心演算法適用條件 貪心演算法的乙個出人意料的應用

ibm ponder this上個月的題目比較有趣 我在心裡面想乙個2到166之間的整數 包括2和166 你的任務是用盡可能少的是非問句 我只能回答是或者否 猜出這個數除1以外的最小約數是多少。1 尋找一種策略使得在最壞情況下猜到答案的詢問次數最少。2 尋找一種策略使得在平均情況下猜到答案的期望詢問...

Python裡出人意料的is運算子

下面是乙個在網際網路上非常有名的例子 a 256 b 256 a is b true a 257 b 257 a is b false a 257 b 257 a is b true is 和 的區別is 運算子檢查兩個運算物件是否引用自同一物件 即,它檢查兩個運算物件是否相同 運算子比較兩個運算物...