1. 程式人生 > >老鼠試毒與位運算

老鼠試毒與位運算

沒有 import int system 表示 map 一點 rgs png

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

首先嘗試解決3只老鼠和8瓶藥水的問題:
解決思路:
給老鼠和藥水分別編號s0, s1, s2; y0, y1, … , y7。

按表中所示給老鼠餵藥,其中1代表老鼠喝了這瓶藥,0代表沒喝。

即老鼠s0喝y4-y7,老鼠s1喝y2,y3,y6,y7,老鼠s2喝y1,y3,y5,y7。y0不給任何老鼠喝。

從表中老鼠喝藥的情況中可以看到,假設y0是毒藥,則沒有老鼠會死;若y3是毒藥,則s1,s2會死;若y7是毒藥,則老鼠全都會死。反過來可以推斷出,假設只有s0死了,則y4是毒藥;若s0, s2死了,則y5是毒藥。

所以,按照表中給出的餵藥方式和老鼠最終的死亡結果,能夠推斷出哪一瓶是毒藥。

嘿嘿嘿,還好我他娘的不是老鼠。

程序模擬:
按照表中的餵藥情況來模擬程序。其中餵藥情況,即老鼠的死亡結果的二進制數,對應了十進制數的0-7,假設死亡結果為3(011B,即s1, s2死亡),則查表可知編號為藥水y3是毒藥(應當理解為map映射,只是本文中恰好以編號3代表那瓶藥水)。

模擬程序如下:

package line.entertain.jerry;

import java.util.Arrays;

/**
* @author line
*/
public class PoisonJerry {

/**
* 根據老鼠死亡結果推斷毒藥編號
* 老鼠:rat, mouse
* 復數:rat -> rats, mouse -> mice
*/ private static int jerry(final int[] rats) { int numOfPoison = 0; for (int i = 0; i < rats.length; i++) { if (rats[i] != 0) numOfPoison += (1 << (rats.length - 1 - i)); } return numOfPoison; } /** * 根據老鼠個數和毒藥編號獲得老鼠死亡結果 * @param numOfRat 老鼠個數 * @param numOfPoison 毒藥編號 */ private static int[] jerry(final
int numOfRat, final int numOfPoison) { /** * 老鼠喝藥情況的數組 * index : 老鼠的編號s0, s1, s2 * value : (value & numOfPoison) != 0 表示老鼠喝過這瓶毒藥,對應index的老鼠給藥死了 */ int[] jerryDrinkPoison = new int[numOfRat]; for (int i = 0; i < numOfRat; i++) { // 初始化喝藥情況 jerryDrinkPoison[i] = 1 << (numOfRat - 1 - i); } for (int i = 0; i < numOfRat; i++) { // 為了看的清楚一點寫了兩個循環 jerryDrinkPoison[i] = (numOfPoison & jerryDrinkPoison[i]) == 0 ? 0 : 1; } return jerryDrinkPoison; } public static void main(String[] args) { /** * 老鼠的死亡情況 */ // int[] deathOfRat = new int[] { 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 }; int[] deathOfRat = new int[] { 0, 1, 1 }; /** * 毒藥的編號 */ int numOfPoison = jerry(deathOfRat); deathOfRat = jerry(deathOfRat.length, numOfPoison); System.out.println(numOfPoison); System.out.println(Arrays.toString(deathOfRat)); } }

假設s1, s2老鼠死亡,則可知y3是毒藥。程序輸入int[] {0,1,1},獲得結果3

技術分享圖片

討論1000瓶藥水的情況:
現有10只老鼠和1000瓶藥水,為每瓶藥水從0開始編號y0-y999,每只老鼠編號s0-s9。再令每只老鼠代表一個二進制位,每一位值為1代表老鼠該老鼠喝下藥水,0表示不喝。例如,藥水y3的餵藥情況: 3 D = 0000000011 B表示老鼠s8, s9喝藥(莫名想笑)。同樣可以根據此種餵藥情況,由老鼠的死亡結果推斷出毒藥編號,或是由毒藥編號推斷出老鼠的死亡結果。

調整程序輸入老鼠的死亡結果 int[] { 0, 0, 0, 1, 1, 0, 1, 0, 1, 1 },可知y107藥水是毒藥。

技術分享圖片

總結:
在百度位運算的時候看到了知乎上這個老鼠餵藥的問題,覺得十分有趣。程序其實不難,但這種位運算的解決思路卻很有想法,故找地方記一下。

老鼠試毒與位運算