智力題還是水有毒 (智力喚醒、簡單代碼、公平性)

前言:
羣裏發現一個很有意思的問題

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

二、思路
對不起,剛開始跑偏了。

自詡數學基礎好、生活經驗豐富的我,思緒飄過二叉樹、布隆過濾器,在奧卡姆剃刀指引下,最終迴歸最基礎的二進制(如果是1024瓶水,保證不跑偏!)。

實際的心路歷程是這樣的:

我的智商可能有問題?
我的智商難道有問題???
我的智商真的有問題!好吧,承認智商有問題後,路就好走了!笨人文化——枚舉!!!
總共一瓶水,其中一瓶水有毒,不用抓小白鼠。
總共兩瓶水,其中一瓶水有毒,抓一隻小白鼠,試喝其中任一瓶,24小時後犧牲了,該瓶水有毒,另一瓶無毒;反之,該瓶水無毒,另一瓶水有毒。【最多犧牲1只小白鼠】
總共三瓶水(編號1、2、3),需要抓兩隻小白鼠,第一隻小白鼠喝瓶1水;第二隻小白鼠喝瓶2水;24小時後,如果有小白鼠犧牲,對應的瓶水有毒;如果都活着,瓶3水有毒。【最多犧牲1只小白鼠】
總共四瓶水(編號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 排列組合角度看公平性
十隻小白鼠都犧牲或都活着的組合:在這裏插入圖片描述

十隻小白鼠犧牲一隻或倖存一隻的組合:在這裏插入圖片描述

十隻小白鼠犧牲二隻或倖存二隻的組合在這裏插入圖片描述

十隻小白鼠犧牲三隻或倖存三隻的組合:在這裏插入圖片描述

十隻小白鼠犧牲四隻或倖存四隻的組合:在這裏插入圖片描述

十隻小白鼠犧牲五隻或倖存五隻的組合:
在這裏插入圖片描述

可以發現:

組合是沒有順序的,機會均等,因此每隻小白鼠犧牲的概率是一樣的。

六、結論:

需要10只小白鼠,來實現任務目標;

每隻小白鼠的使命和壯烈概率基本相同;

最幸運的情形,所有小白鼠都倖存;

【比如將1000的二進制表示替換成0000000000,即第1000瓶不給小白鼠喝】

最不幸的情形,只有一隻小白鼠倖存。

向獻身醫學的小白鼠致敬!!!

歡迎關注,敬請點贊!

討論交流:313074041

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