題有毒,還是智力有問題——瓶水有毒[智力題?!智力喚醒、簡單代碼、公平性]
一、智力題??!
有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瓶不給小白鼠喝】 - 最不幸的情形,只有一隻小白鼠倖存。
向獻身醫學的小白鼠致敬!!!
歡迎關注,敬請點贊!
返回頂部