精華區beta Programming 關於我們 聯絡資訊
先說明題目,就是有 n(通常是4,後面就以4討論之)位數,其 數字不可重複,你可以先猜一個4位數,然後它會告訴你,幾A幾B, 然後你可以再根據提示輸入一個4位數,它再告訴你幾A幾B,直 至你答到4A。 這個問題之前已有很多人討論過,但精華區卻都沒收錄,我便自把 我所能看到的舊信,整理一下,和大家討論。 目前最常用,也是最容易 implement 的方法,就以建 answer list 的方法,就是把所有的可能的答案(5040個)建成一個 list,每次從可能答案的 list 中,「隨便」選一個來猜,再由 所得的提示,把不可能的答案去除,再由可能的答案中再「隨便」 選一個來猜,直至4A為止,一般這個方法「平均」 6-7 次就可以 猜出答案,但最糟的時候會有8次,但不常見。 但這個方法只是由答案中「隨便」選一個來猜,並不能保證是最佳 的猜法,也不能確保worse case 舉例來說, 若是 答案是 1230,你一開始(運氣很好,第一次就3A)猜 1234 -> 3A 若是用上面的演算法,運氣又很不好時,可能會有 1235 -> 3A 1236 -> 3A 1237 -> 3A 1238 -> 3A 1239 -> 3A 1230 -> 4A 共要猜 7 次, 但若是先猜一次 5678,無論是得到 0A0B, 1A, 或 1B, 都能保證在"6次"內猜出來。 再舉另一個例子,要猜0-100中的一個數字,猜了後,它會給你 有答案比猜的數大或小的提示,我們知道用二分法來做,一定能 保證7 次內一定可以猜中此數字 (2^7=128>101),但若是用 上面的演算法,「可能」(雖然機率不大)會出現 50 -> small 49 -> small 48 -> small : : 0 -> YOU GOT IT 共猜 51 次, 當然實際上不會這麼極端,平均仍在 7-9 次之間就可猜出, 但其 WORSE CASE 就十分不好。 所以上面的演算法,隨便猜一個四位數,幾A幾B的,就有可 能到 8 次。 所以到底怎麼猜是最佳的演算法,目前可以看到是AI(人工 智慧)的方法,把問題看成game search,雖然 search space 只有 5040,但 branch factor 的分很 大,(隨便猜只是其中的一個分枝),其中我看吳慶鴻 (woju@bbs.ee.ntu.edu.tw)同學有較詳細的 implement ,如下: > 1. 猜對方的數字時儘量例用「所有已知資料」,從中找出最 佳的幾個解,並計算 (模擬)出那個答案會讓對方作弊 的機會降到最低,模擬深度只有一層,也就是 local optimal,類似象棋推測對方下一步棋一樣。 > 2. 儘可能的做弊,並使用類似 Step 1 的方法找出最佳做 弊解,儘可能讓對方猜中的可能降低 > 3. 當對方做出「不合理的弊」時,可以抓包... > 此程還有改進的空間,比如說,把 local optimal 擴展至 global optimal,不過這樣大概得用更快的電腦了... 但他的不沒有列出他的方法「平均要猜幾次」,「最糟要猜幾次」。 還有一位同學(夜 就是我的全部,Willy.bbs@cis.nctu.edu.tw) > 當初想這演算法的原因是班上有一位同學,玩猜數字遊戲幾乎 不超過五次的。在屢戰屢敗下受了刺激,才進而一步步的想, 數字該怎麼取比較好,慢慢歸納出十幾項規則,最後便依照這 些「鐵則」寫成 pseudo-code,無奈正逢高三要考聯考,家 裡電腦被封機,就沒能完成程式。 等考完,那心血就不知道夾到那本書中賣掉了﹍﹍ 三次找出正確數字、五次排出順序看似不可能,但當初確是經過 多位同學以人工方式依虛擬碼一步步操作,而得出的結果。也曾 經不先決定數字,而取最差的狀況,結果仍然一樣五次內解出。 如今每當見到大家討論這問題,都不禁令我心中欷噓,怎會丟掉呢 ?唉﹍﹍ 這位同學,加了許多自已的heuristic, 可惜演算法不見了,十分可 惜,不過三次要找到正確字,的確十分不可能,若是第一次猜1234, 得到1B,第二次大概只能猜5678,又得到2B,我無法知道(想像), 能在第三次就能知道1234中的那一個,5678中的那二個,和90中的那 一個 :< 。 不過我覺得可能會有一種猜法,平均 5-6 次,最糟只要 6次。 討論這麼多,希望有作出較好的方法的同學們,甚至已用數學(程式) 推導最佳解的天才,能給一些意見,或是一起討論一下,再AI中可以 用那些方法找出較好的猜法,或是有較好的 heuristic可以用在 implement 上. -- 蘇明信 simon@iis.sincia.edu.tw