看到今天一道算法题,就写了一下自己的思路,希望有大牛,看到这个题,能提出更好的想法,再进行交流学习,我只用了一点简单的C++ 进行实现
有15个瓶子,其中最多有一瓶有毒,现在有四只老鼠,喝了有毒的水之后,第二天就会死。如何在第二天就可以判断出哪个瓶子有毒
我的想法是,因为最多有一瓶有毒,所以只有,0瓶有毒,或者其中一瓶有毒,所以是16种状态,所以用4只老鼠的喝下水的存活状态标级 '0' 或者 '1',来进行标记对应的瓶子
0000 => 无毒
0001 => 1号瓶
0010 => 2号瓶
0011 => 3号瓶
0100 => 4号瓶
0101 => 5号瓶
0110 => 6号瓶
0111 => 7号瓶
1000 => 8号瓶
1001 => 9号瓶
1010 => 10号瓶
1011 => 11号瓶
1100 => 12号瓶
1101 => 13号瓶
1110 => 14号瓶
1111 => 15号瓶
将水喂给当前瓶子编号每一位为 '1' 的老鼠,例如第7号瓶子,则给第二只,第三只,第四只老鼠喂瓶子里面的水,最后观察老鼠的存活状态,来判断是哪一瓶,比如最后是 '1011' 则是11号瓶有毒。
实现的算法如下:、
#include <iostream>
using namespace std;
int main(){
const int MOU_NUM = 4;//老鼠数量
int mouse[MOU_NUM] = {0};//老鼠状态,'0'为存活,'1'为死亡
int drug = 0;//有毒瓶子号
for (int i = 0; i < MOU_NUM; i++)
{
cin>>mouse[i];//输入老鼠喝水后的存活状态
}
for (int i = 0; i < MOU_NUM; i++)
{
drug |= (mouse[i] << (MOU_NUM - i - 1));//进行位运算
}
//判断是否有毒
if (drug == 0)
{
cout<<"没有有毒的"<<endl;
}
else{
cout<<"有毒的是第"<<drug<<"瓶";
return 0;
}
}
核心的代码是第二个for循环中进行位运算的语句。运算分析过程如下:
首先是<<左移位运算符。
mouse[i] << (MOU_NUM - i - 1)
上面代码的意思mouse[i]所对应的二进制数字进行左移MOU_NUM - i - 1位,移动之后将左边自动补零。例如1<<2变成100,实际上相当于4,也就是1*2^2,因此对于a<<b,相当于a*2^b,也就是将a扩大2^b倍。
所以第二个for循环实际上是将for与左移之后的mouse[i]进行或运算。具体的运算过程如下:
如果输入1011,则mouse[0]=1,,mouse[1]=0,mouse[2]=1,mouse[3]=1
i=0时,drug=0,0|=(mouse[0]<<(4-0-1))
相当于0|=(1<<3),也就是0|=1*2^3,即0|=1000,相当于000|=1000,故drug=1000
i=1时,drug=1000,1000|=(mouse[1]<<(4-1-1))
相当于1000|=(0<<2),也就是1000|=0*2^2,即1000|=0,相当于1000|=0000,故drug=1000
i=2时,drug=1000,1000|=(mouse[2]<<(4-2-1))
相当于1000|=(1<<1),也就是1000|=1*2^1,即100|=2,相当于1000|=0010,故drug=1010
i=3时,drug=1010,1010|=(mouse[3]<<(4-3-1))
相当于1010|=(1<<0),也就是1010|=1*2^0,即1010|=0001,相当于1010|=0001,故drug=1011
二进制的1011就是十进制的11。