有难度的算法笔试题
摘自:
http://community.csdn.net/Expert/TopicView3.asp?id=57649203)芯片测试:
有2k块芯片,已知好芯片比坏芯片多。请设计算法从其中找出一片好芯片,说明你所用的比较次数上限。
其中:
好芯片和其它芯片比较时,能正确给出另一块芯片是好还是坏。
坏芯片和其它芯片比较时,会随机的给出好或是坏。
Vitin(卫亭) ( ):
试着回答一下第三题,不保证最快效率:
1.对N个芯片,在保证好芯片比坏芯片多的情况下,取出一块芯片(为叙述方便,设为芯片X),与其他所有芯片做测试,记录相互间的结果.
2.按照芯片X对其他芯片的结果,将其他芯片分成两组:GOOD组和BAD组.
3.如果GOOD组的数目<BAD的数目,则X为坏芯片,跳到5.
4.
如果GOOD组的数目>=BAD组的数目,并且GOOD组对X的测试为good(认为X好芯片),则X确实是好芯片,算法结束(因为在N-1中,至
少半数的芯片认为X为不是坏芯片,考虑到"好芯片比坏芯片多",可归谬证明);否则,只要有一个GOOD组芯片对X的测试为bad,则X为坏芯片,继续.
5.X为坏芯片,故去除X,将所有芯片分成两组:对X的测试为bad的保留,对X的测试为good的去除.考虑到所有的好芯片都保留了(它们对X的测试必为bad),所以仍然满足"好芯片比坏芯片多"的条件.跳到1,继续.
以上算法保证可以结束.因为如果测试出X是坏的,那么每次N至少减一.并且,因为"好芯片比坏芯片多",算法必定是在第4步结束.而不会出现芯片降到1的情况(只要初始的芯片数>=2)
题目中,初始N=2k.其复杂度在最坏的情况下测试次数(假设一次测试同时出现相互的结果,否则次数*2)为: k + (k+1) + ... + (2k-1) = 1/2 * k(3k-1) = O(k^2)
xlfddlfd(楼主请点我加分^_^不用客气) ( ) :
下面两个结论比较有用,先列出来。
任意拿两片芯片互相测试,则有
1)结果都为真,则说明两片都为真,或者都为假。
2)其他结果,则最少有一为假。
在任意偶数多的芯片里,如果好芯片多于坏芯片,将所有芯片两两分组,根据抽屉原理,则有
1)必有两个好芯片分在一组。
2)同为好芯片的组数一定多于同为坏芯片的组数。
测试流程
1)将芯片两两分组,比如1和2,3和4。。。。2k-1和2k。互相测试,则必有结果同为真的组。
2)保留结果同为真的组,丢弃其他组。必有好芯片组多于坏芯片组。(所以当只有两组或者一组同为真时,则必为真,测试结束)
3)结果同为真的组芯片必定同好或者同坏,所以可以丢弃一半。从所有同真组中任意取出一个丢弃另一个,组成新的测试组,继续两两分组,直到同真组只有2个或者1个测试结束,坚持到最后的就是好芯片。
说
明:同真组可能会变成奇数个,当为奇数组时,任意选一组取其中一个(假设为A),在剩余组中各取一个来测试A,如果测试结果A为好芯片过半或者等于一半,
则A为好芯片,测试结束。否则A为坏芯片,判定A为好芯片的必为坏芯片,剔除后剩余部分形成新的测试组,继续两两分组。。。
总的原理和淘
金差不多,刚开始好的芯片多,在每次剔除芯片时一定要保证剔除的坏芯片数量一定要多于或者等于好芯片的数量,这样就能保证在剩余的芯片中好的一定多于坏
的。当组数为奇数时采用投票制,多于半数的投票有效(等于也有效,因为好的多于坏的,相等则被测试的一定为好的)。
因为每次最少剔除一半的芯片,所以最坏情况出现在每次只能剔除一半芯片的时候,按等比数列递减。当有N个芯片时,测试次数为n+(n/2)+(n/4)...=2n(实际上当为奇数组时,次数会更多,不过算不过来了,省略^_^ )
Vitin(卫亭) ( ) :
xlfddlfd 的算法很好,学习一下.
这个算法比我之前的算法要快得多.
当
最坏情况是,每次都是奇数,并且每次都是坏芯片 时,测试次数(lg是以2为底的对数,N = 2k)约为 2(k + k/2 +
k/4+...)-slgk = 4k - slgk =
O(k),仍然是线性算法(此处的s为不大的常数(但大于1),因为在每次为奇数的情况下,实际的数目要比 k/2, k/4
之类的小,可以认为这个误差是lgk的倍数,此外坏芯片的比较数是每次总个数-1,所以要减少大约一个lgk).