芯片检测(分治法经典问题)

1. 问题描述

有一批芯片(n片),里面有好芯片有坏芯片,我们不知道哪片是好的哪片是坏的,只知道里面的好芯片一定比坏芯片至少多出一片
现在有一个检测设备,同时将两片芯片放进去,它们会各自报告对方的情况,好芯片的报告结果一定是真实的,坏芯片的报告结果是不确定的(有可能是真实的,也有可能是假的)。会有这样的报告结果:

芯片A的报告 芯片B的报告 结论
AB都好或者都坏
假如两个都是好的,显然矛盾了,因此至少有一个坏的
同上,至少有一个坏的
反证,可得至少一个是坏的

现在要求从这批芯片中挑出一个好的芯片。
从这批芯片当中随便挑出一个芯片,用剩下的芯片挨个去和它进行检测。
当n为偶数时:

待测试芯片 其余芯片(奇数个)
好芯片 剩余芯片中好芯片的个数仍然会比坏芯片至少多一片,因此将会有超过一半的芯片报告是好芯片
坏芯片 同上,有超过一半的芯片报告是坏芯片

当n为奇数时

待测试芯片 其余芯片(偶数个)
好芯片 剩余芯片中好芯片的个数不会比坏芯片少,因此将会有至少一半的芯片报告是好芯片
坏芯片 剩余芯片中好芯片的个数比坏芯片多至少两片,因此将有超过一半的芯片报告是坏芯片

推论1: 从n个芯片中随便挑出一个,如果是好芯片,则至少有一半的芯片报告为“好”;
逆否命题:如果报告结果为好的少于一半,那么这一定不是一个好芯片(那就是坏芯片了)。
推理2: 从n个芯片中随便挑出一个,如果是坏芯片,则应有超过一半的芯片报告为“坏”;
逆否命题:如果报告结果为坏的芯片至多一半,那么这肯定不是坏芯片(那就是好芯片了)。

2. 常规法

  1. 芯片总数为偶数(2k):
    挑出一个芯片X(待检芯片)后,剩下(陪检芯片)奇数个(2k-1),在这2k-1个中,好的肯定比坏的多。检测报告(只看陪检芯片的报告)有如下两种情况:
陪检芯片报告 结果分析
报好多于报坏 X肯定是好芯片。因为如果A是坏芯片,又发布报告的芯片中好芯片多,那么结果中报坏的肯定要多于报好的。
报坏多于报好 X肯定是坏芯片。原因同上,因为发布报告的芯片中好芯片占有优势。
  1. 芯片总数为奇数(2k+1):
    挑出一个芯片X后,剩下奇数个(2k),在这2k个中,好的至少也占了半数。检测报告有如下三种种情况:
陪检报告 结果分析
好坏各占一半 根据推理2的逆否命题,这肯定不是坏芯片,那X就是好芯片了。或者我们来反证一下,假如是坏芯片,那么剩余的2k个芯片中好的就不只半数了,至少也比坏的多两个,否则与大前提(在一批芯片中好的至少比坏的多1个)矛盾。这样的话,报告里报坏的就不止一半了,而是多于一半,这与我们看到的报告不相吻合,因此X一定是好芯片。
好多于坏 因为陪检芯片中至少有一半好芯片,所以如果是坏芯片,那么报坏的芯片数不可能比少于一半。因此这是好芯片
坏多于好 同上,这是坏芯片

以上我们从各种情况分析得出了当面对这一堆芯片的分析报告时,我们如何去判断这是什么样的芯片。
现在再来解决这个问题,算法很简单:挑出一个芯片X,用剩余的检测它,然后看它是否是好芯片,如果是则完成问题,如果不是则再换一个进行检测,直到我们挑出一个好的为止。
算法分析:每次挑选需要O(n)次检测,运气好的话第一次就挑中了一个好的,运气不好最多只需要n/2次(上取整)。平均的话需要两次。

3. 分治法

我们能想到的做法是,先两两一组进行检测,如果两个报告都是好(这两个芯片同好或同坏),则将这两个芯片任意留下一片,否则就将这两个芯片都舍弃。然后按同样的做法对剩下的进行下一轮的检测。
能否行的通?分治法的关键在于子问题和原问题应该有相同的性质。也就是说,经过一轮检测,剩下的芯片中仍然应该保持着好的至少比坏的多一个这条性质
证明:

  1. 假如芯片数为偶数
    • 设在决定任留一个的芯片对中同为好的有2k个(任留其中一个),同为坏的有2j个(任留一个),舍弃的芯片中,好的m个坏的n个(因为在上面的分析中可以看到,舍弃的情况中都是坏的至少一个,也就是说n >= m)。
    • 根据题设有,2k + m > 2j + n。
    • 综合上面的可知,2k > 2j,即k > j,也就是说剩下来的芯片中,好的仍然比坏的多。
  2. 假如芯片数为奇数
    • 设在决定任留一个的芯片对中同为好的有2k个(任留其中一个),同为坏的有2j个(任留一个),舍弃的芯片中,好的m个坏的n个(因为在上面的分析中可以看到,舍弃的情况中都是坏的至少一个,也就是说n >= m),还有一个没有参加检测的。
    • 根据题设有,2k + m >= 2j + n,注意这里取等号了,因为剩下的那个有可能是好的。
    • 综合上面的可知,k >= j,也就是说剩下来的芯片中,好的不能保证比坏的多了。
    • 这个时候就应该对剩余的那个进行一次检测了,用留下的芯片对其进行一次检测,因为剩下的芯片中好的至少还是占了一半,因此如果报告中好的报告占一半或以上,那么这个就是好芯片,将其留下,那么我们就直接完成了这个问题,找到一个好芯片。否则直接将它丢掉。因为我们已经知道了未参加检测的那个是坏芯片,这时我们再来看第2条,会发现2k + m >= 2j + n + 2,那么显然k > j成立,保持了原来的好的至少比坏的多一个的性质。

算法分析:分治法的时间复杂度递推方程为W(n) = W(n/2) + n/2,n/2是两两分组需要进行的检测次数,在出现有奇数个芯片的时候,有一个剩下的,需要额外进行最多n/2次(因为2k + 2j < 芯片总数,那么k+j 一定小于总数的一半)检测,但是却有一半的几率使递归提前终止(剩下的那个是好的)。最终的综合检测次数为O(n)。

4. 总结

总的来看,分治法稍稍好一些。但是其实常规法也不错,因为我们知道,前3次都没挑到好芯片的概率小于12.5%,前四次都没挑到的概率小于7.5%,…,前7次都没条中的概率小于1/128=0.78%,已经不足1%了,基本上我们可以假定只需要不超过7次就可以挑到一个好芯片。因此其实常规法的效率也不错,而且因为不需要递归,节省了空间。但是常规法需要大量的分析。花了一下午分析写这个东西,打乒乓球去了。

你可能感兴趣的:(算法,分治算法)