題有毒,還是智力有問題——瓶水有毒[智力題?!](智力喚醒、簡單代碼、公平性)

歡迎關注,敬請點贊!

一、智力題??!

有1000瓶水,其中有一瓶有毒,小白鼠只要嘗一點帶毒的水24小時內就會死亡,至少要多少隻小白鼠才能在24小時內鑑別出哪瓶水有毒?【題目肯定經不起吃瓜大衆的推敲,我們還是按出題人的思路來!】
智力題

二、思路

返回頂部
對不起,剛開始跑偏了。
自詡數學基礎好、生活經驗豐富的我,思緒飄過二叉樹、布隆過濾器,在奧卡姆剃刀指引下,最終迴歸最基礎的二進制(如果是1024瓶水,保證不跑偏!)。
實際的心路歷程是這樣的:

  1. 我的智商可能有問題?
  2. 我的智商難道有問題???
  3. 我的智商真的有問題!
    好吧,承認智商有問題後,路就好走了!笨人文化——枚舉!!!
  4. 總共一瓶水,其中一瓶水有毒,不用抓小白鼠。
  5. 總共兩瓶水,其中一瓶水有毒,抓一隻小白鼠,試喝其中任一瓶,24小時後犧牲了,該瓶水有毒,另一瓶無毒;反之,該瓶水無毒,另一瓶水有毒。【最多犧牲1只小白鼠】
  6. 總共三瓶水(編號1、2、3),需要抓兩隻小白鼠,第一隻小白鼠喝瓶1水;第二隻小白鼠喝瓶2水;24小時後,如果有小白鼠犧牲,對應的瓶水有毒;如果都活着,瓶3水有毒。【最多犧牲1只小白鼠】
  7. 總共四瓶水(編號1、2、3、4),需要抓兩隻小白鼠,第一隻小白鼠喝瓶1、3水各1滴;第二隻小白鼠喝瓶2、3水各1滴;24小時後,如果只有第一隻小白鼠犧牲了,瓶1水有毒;如果只有第二隻小白鼠犧牲了,瓶2水有毒;如果兩隻小白鼠都犧牲了,瓶3水有毒;如果都活着,瓶4水有毒。【最多犧牲2只小白鼠】
    ……
    簡而言之:不同瓶號的水,讓不同小白鼠組合來喝;根據犧牲的小白鼠組合,可反推出哪瓶水有毒。
    終於回憶起二進制這個熟悉的陌生人了!

三、二進制表示

【小白鼠從右往左編號】
第一瓶水,取一滴只給第一隻小白鼠喝,二進制表示0000000001;
第二瓶水,取一滴只給第二隻小白鼠喝,二進制表示0000000010;
第三瓶水,取兩滴,分別給第一隻、第二隻小白鼠喝,二進制表示0000000011;
第四瓶水,取一滴只給第三隻小白鼠喝,二進制表示0000000100;
第五瓶水,取兩滴,分別給第一隻、第三隻小白鼠喝,二進制表示0000000101;
第六瓶水,取兩滴,分別給第二隻、第三隻小白鼠喝,二進制表示0000000110;
第七瓶水,取三滴,分別給第一隻、第二隻、第三隻小白鼠喝,二進制表示0000000111;
……
第511瓶水,二進制表示0111111111;
……
第767瓶水,二進制表示1011111111;
……
第999瓶水,二進制表示1111100111;
第1000瓶水,二進制表示1111101000。
【因10個二進制位最多可以表示0~1023共1024種狀態,1024>1000,因此可以將任意一瓶的二進制表示替換成0000000000(所有小白鼠都不喝),其它瓶仍然按照編號對應的二進制】

四、簡單python代碼實現

4.1 假設有毒水瓶號,斷言犧牲的小白鼠編號

返回頂部

def mouse(n):
    mouse_die = []
    i = 1
    while n:
        n, m = divmod(n, 2)
        if m:
            mouse_die.append(i)
        i += 1
    return mouse_die

print('第5瓶水有毒時,犧牲的小白鼠編號:', mouse(5))
print('第21瓶水有毒時,犧牲的小白鼠編號:', mouse(21))
print('第511瓶水有毒時,犧牲的小白鼠編號:', mouse(511))
print('第767瓶水有毒時,犧牲的小白鼠編號:', mouse(767))
print('第999瓶水有毒時,犧牲的小白鼠編號:', mouse(999))
print('第1000瓶水有毒時,犧牲的小白鼠編號:', mouse(1000))

運行結果:

5瓶水有毒時,犧牲的小白鼠編號: [1, 3]21瓶水有毒時,犧牲的小白鼠編號: [1, 3, 5]511瓶水有毒時,犧牲的小白鼠編號: [1, 2, 3, 4, 5, 6, 7, 8, 9]767瓶水有毒時,犧牲的小白鼠編號: [1, 2, 3, 4, 5, 6, 7, 8, 10]999瓶水有毒時,犧牲的小白鼠編號: [1, 2, 3, 6, 7, 8, 9, 10]1000瓶水有毒時,犧牲的小白鼠編號: [4, 6, 7, 8, 9, 10]

4.2 根據犧牲的小白鼠編號組合,反推有毒水瓶號

def water(lt):
    water_num = 0
    for i in lt:
        water_num += 2 ** (i - 1)
    return water_num
    
print('犧牲的小白鼠編號爲:[1, 3]時,有毒的水瓶號是:', water([1, 3]))
print('犧牲的小白鼠編號爲:[1, 3, 5]時,有毒的水瓶號是:', water([1, 3, 5]))
print('犧牲的小白鼠編號爲:[1, 3, 6, 7, 8]時,有毒的水瓶號是:', water([1, 3, 6, 7, 8]))

運行結果:

犧牲的小白鼠編號爲:[1, 3]時,有毒的水瓶號是: 5
犧牲的小白鼠編號爲:[1, 3, 5]時,有毒的水瓶號是: 21
犧牲的小白鼠編號爲:[1, 3, 6, 7, 8]時,有毒的水瓶號是: 229

五、公平性說明

返回頂部
善良的小夥伴,不必像我一樣擔心第一隻小白鼠喝太多撐着(或犧牲概率太大),每隻小白鼠喝的基本一樣多(賭中死亡輪盤的概率是一樣的)。
第一隻小白鼠(試喝1、3、5、……),隔1瓶(號)試喝1瓶(號)裏的一滴水。
第二隻小白鼠(試喝2、3、6、7、10、11、……),隔2瓶(號)試喝2瓶(號)裏的一滴水。
第三隻小白鼠(試喝4、5、6、7、12、13、14、15、……),隔4瓶(號)試喝4瓶(號)裏的一滴水。
……
第十隻小白鼠(前面511瓶不用試喝,後面都試喝)。
如果是1024瓶水,每隻小白鼠都喝512瓶(所有小白鼠都不喝第1024瓶),第十隻小白鼠(試喝512、513、514、……、1023)。

5.1 排列組合角度看公平性

十隻小白鼠都犧牲或都活着的組合:C100=C1010=10!0!×(100)!=1C_{10}^0 = C_{10}^{10} = \frac{10!}{0! × (10-0)!} = 1
十隻小白鼠犧牲一隻或倖存一隻的組合:C101=C109=10!1!×(101)!=10C_{10}^1 = C_{10}^9 = \frac{10!}{1! × (10-1)!} = 10
十隻小白鼠犧牲二隻或倖存二隻的組合:C102=C108=10!2!×(102)!=45C_{10}^2 = C_{10}^8 = \frac{10!}{2! × (10-2)!} = 45
十隻小白鼠犧牲三隻或倖存三隻的組合:C103=C107=10!3!×(103)!=120C_{10}^3 = C_{10}^7 = \frac{10!}{3! × (10-3)!} = 120
十隻小白鼠犧牲四隻或倖存四隻的組合:C104=C106=10!4!×(104)!=210C_{10}^4 = C_{10}^6 = \frac{10!}{4! × (10-4)!} = 210
十隻小白鼠犧牲五隻或倖存五隻的組合:C105=10!5!×(105)!=252C_{10}^5 = \frac{10!}{5! × (10-5)!} = 252
可以發現:210=1024=i=010C10i2^{10} = 1024 = \displaystyle \sum_{i = 0} ^{10} C_{10} ^i
組合是沒有順序的,機會均等,因此每隻小白鼠犧牲的概率是一樣的。

六、結論:

  1. 需要10只小白鼠,來實現任務目標;
  2. 每隻小白鼠的使命和壯烈概率基本相同;
  3. 最幸運的情形,所有小白鼠都倖存;
    【比如將1000的二進制表示替換成0000000000,即第1000瓶不給小白鼠喝】
  4. 最不幸的情形,只有一隻小白鼠倖存。

向獻身醫學的小白鼠致敬!!!
歡迎關注,敬請點贊!
返回頂部

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章