二进制的二三事 | Parallel Labs
Task1:求一个固定长度集合所有子集
二进制版本
Task2:小白鼠试毒药问题
实验室里有1000个一模一样的瓶子,但是其中的一瓶有毒。可以用实验室的小白鼠来测试哪一瓶是毒药。如果小白鼠喝掉毒药的话,会在一个星期的时候死去,其他瓶子里的药水没有任何副作用。请问最少用多少只小白鼠可以在一个星期以内查出哪瓶是毒药?
Read full article from 二进制的二三事 | Parallel Labs
Task1:求一个固定长度集合所有子集
例如集合{a, b, c, d, e}中的子集{a, b, c}可以用“11100”来表示,子集{c, d, e}可以用“00111”来表示,空子集{}可以用“00000”来表示。
那么对任意固定长度的集合a[n],我们可以从a[0]开始穷举a[0]在子集中和a[0]不在子集中两种情况,再依次类推从a[1]开始一直穷举到a[n-1]为止。于是我们可以得到一个很直观的递归程序:
void
sub_sets_recu(
int
index,
int
length,
char
*array,
char
*bits)
{
int
j = 0;
if
(index >= length) {
for
(j = 0; j < length; j++) {
if
(bits[j] ==
'1'
) {
printf
(
"%c"
, array[j]);
}
}
printf
(
"\n"
);
}
else
{
bits[index] =
'1'
;
sub_sets_recu(index+1, length, array, bits);
bits[index] =
'0'
;
sub_sets_recu(index+1, length, array, bits);
}
}
void
sub_sets_iter(
int
length,
char
*array)
{
int
i = 0;
int
j = 0;
for
(i = 0; i < (1<<length); i++) {
for
(j = 0; j < length; j++) {
if
((i & (1<<j)) != 0) {
printf
(
"%c"
, array[j]);
}
}
printf
(
"\n"
);
}
}
Task2:小白鼠试毒药问题
实验室里有1000个一模一样的瓶子,但是其中的一瓶有毒。可以用实验室的小白鼠来测试哪一瓶是毒药。如果小白鼠喝掉毒药的话,会在一个星期的时候死去,其他瓶子里的药水没有任何副作用。请问最少用多少只小白鼠可以在一个星期以内查出哪瓶是毒药?
这个问题关键是跳出思维,并不是说瓶子和小白鼠必须一一对应,然后我们用1000只小白鼠,每只各试一瓶药水,等一个礼拜然后出结果。其实我们仔细想想,小白鼠试毒只有两种结果,非“死”即“生”,又是一个0/1状态。很显然我们可以再次构建一个0/1组成的二叉树,由此即可表示不同的试毒结果。假设我们需要n个小白鼠,那么2^n-1应大于等于1000(因为有1000种可能的结果,减一是指要除去小白鼠全部不死的情况 — 多谢danqi指正),那么最小的n就是10了
解决此类问题的关键在于找到能用0/1表示的状态,然后想办法用0/1组成的二进制数来表示不同的结果,从而达到节省存储空间,提高解题效率的目的。Read full article from 二进制的二三事 | Parallel Labs