一道發散思維題,有1000個一模一樣的瓶子,其中有999瓶是普通的水,有一瓶是毒........

題目:有1000個一模一樣的瓶子,其中有999瓶是普通的水,有一瓶是毒藥。任何喝下毒藥的生物都會在一星期之後死亡。現在,你只有10只小白鼠和一星期的時間,如何檢驗出那個瓶子裏有毒藥?

最近在知乎上看到很火的一個問題,如何看待清華大學自動化系2020年大一c++大作業是寫一個功能更強大的雨課堂(雷課堂)?

翻着翻着看到了騰訊給的一個面試題目,也就是上面那個。拿到題目那一刻,當時立馬想到了用二分法。於是在本子上開始畫,畫着畫着發現不對了,只有一週的時間。不能一個接一個去檢測,那該咋做?說來慚愧,作爲計算機專業的學生,實在是沒想到好的方法解出來。 看了一下別人的思路說用二進制數來表示,每一個老鼠對應一位,最後看老鼠的存活情況(0死亡,1存活),就可以對應出是哪瓶有毒了。

!!秒啊!!

於是我開始從大腦裏回憶我那殘留的毛皮計算機組成原理的知識,想到了內存映射。突然發現我以前從來沒有想過爲什麼使用二進制能剛好對應一個位置。 比如,101 對應10進制數 5,如果8個盒子擺在面前(編號0-7),怎麼通過3位二進制去選到5號這個盒子呢?

盒子:0-1-2-3-4-5-6-7

假設將盒子分爲兩半,二進制0代表選前一半,1代表選後一半

以101爲例,從左至右:

第一位是1,那麼意味着我的目標定位到後4個盒子也就是(4,5,6,7);

第二位是0,選(4,5,6,7)的前一半(4,5)

第三位是1,選(4,5)後一半得到5

如此就剛好定位到5了。這裏我們是通過二進制數來找對應位置。

那麼回到題目,我們如何用二進制來找到毒藥呢?

這道題目巧妙的就是用老鼠是否毒發來代表0,1,從數量反過來編碼二進制。

分析題目:

第一隻老鼠用來實驗一半的水,假設爲A.

第二隻老鼠則確定A中的一半的水,所以是喝其中的A/2的水嗎?

依此類推,第三隻老鼠,第四隻。。。。。

其中有個問題,這個A可能是所有水的前一半也可能是後一半,第一隻老鼠毒發則確定在後半部分,存活則是在前半部分。第二隻老鼠則要在對應半個部分再劃分確定一半。由於A是不確定的,有兩種可能,所以不能只在一半部分取,我們分別在前半部分和後半部分各取一半這樣就可以定位到對應的位置了。不懂?見下面的例子!

假設8瓶水 0,1,2,3,4,5,6,7

#以下左邊括號代表爲二進制0,代表沒有餵給老鼠的對應的水編號;右邊代表二進制1,代表喝的水對應編號

1號老鼠:(0,1,2,3): 0<=||=>1 :(4,5,6,7)

2號老鼠:((0,1),(4,5))0<=||=>1 ((2,3),(6,7)  )   

2號找上面1號的一半的一半,比如,((2,3),(6,7)  )   對應了無論1號是否毒發,2號毒發的對應的瓶子。

3號老鼠:((0),(4),(2),(6))0<=||=>1 ((1),(5),(3),(7 ))   也就是2號的一半的一半,同理

其實原理和二分法類似,但是這裏是確定了一半的同時另一半也要確定了下來,所以每隻老鼠都會喝下一半的水。

我們模擬一下,假如1號毒發,則在(4,5,6,7)中確定;  1號毒發編碼爲1

2號喝了1號的對應後半部分(2,3),(6,7) ,如果2號也毒發了,根據上面1號毒發的情況在(4,5,6,7)中確定,我們就可以在((2,3),(6,7)  )  確定(6,7) ,沒有毒發則在(0,1),(4,5))確定(4,5); 這裏假設2號未毒發則在(4,5)中確定一個。  2號未毒發編碼爲0

三號老鼠則喝了二號對應的一半的一半((1),(5),(3),(7 )),假如3號也毒發,則在根據2號的情況((1),(5),(3),(7 ))中確定了(5)。3號也毒發編碼爲1

所以最後從上到下的編碼就是101=5號

我想了想,其實這就是二叉樹進行編碼的例子(具體請看數據結構,類似哈夫曼編碼),突然遇到這種實際情況的題目很難反應過來,要是直接告訴我:1000個數要用多少個二進制進行編碼我肯定立馬就想到了。

感覺還是得回去看看數據結構順便得結合一些實例來看。

最後一個問題來了!一下喝500瓶水老鼠會不會漲死?  。。。。。。當然我們還是可以把水混合着喂。

 

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