一、问题描述
有n片芯片,其中好芯片比坏芯片至少多1片,现需要通过测试从中找出1片好芯片。测试方法是:将2片芯片放到测试台上,2片芯片互相测试并报告测试结果:“好”或者“坏”。假设好芯片的报告是正确的,坏芯片的报告是不可靠的 (即对于被测试的芯片显示的报告可能是坏或者好)。请设计一个算法,使用最少的测试次数来找出1片好芯片。
测试函数可以采用以下方法。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//建立测试函数,参数i表示主动测试芯片, iB表示被测芯片.返回值为被测芯片的测试值
//值为1时表示好芯片,为0时表示坏芯片.
//应用随机数来表示不确定的值1、0.注意:在主函数中加上随机数种子语句srand(time(NULL));
//算法的输入可以用数组表示,比如:ABc[17]={1,0,0,1,1,1,0,0,1,1,1,1,0,1,0,0,0} 表示17个芯片,其中9片好芯片、8片坏芯片。
int X_test(int iA,int iB)
{
if(iA==1)
return iB;
return rand()%2;
}
二、问题分析
本问题采用的主要思想是分治策略。将n片芯片两两一组分成 ⌊ n 2 ⌋ ⌊\frac n 2⌋ ⌊2n⌋ (向下取整) 组,每组测试1次,通过第一轮的 ⌊ n 2 ⌋ ⌊\frac n 2⌋ ⌊2n⌋ 的测试淘汰一部分芯片,剩下的芯片构成一个规模较小的子问题进入第二轮。如果测试的芯片不超过3片 (即子问题规模小于等于3) ,并且好芯片比坏芯片至少多1片,那么只要测试1次就可以找出好芯片。
而上面所说的淘汰规则需要符合好芯片比坏芯片至少多1片的条件,所以采用的淘汰规则是:
结果是情况1(下图)时,那么A、B中留1片,丢掉1片;如果时后三种情况,则把A和B全部丢掉。(在此不做证明)
情况 | A报告 | B报告 | 结论 |
---|---|---|---|
1 | B是好的 | A是好的 | A,B都好或A,B都坏 |
2 | B是好的 | A是坏的 | 至少1片是坏的 |
3 | B是坏的 | A是好的 | 至少1片是坏的 |
4 | B是坏的 | A是坏的 | 至少1片是坏的 |
具体算法思想步骤:
1、芯片数 n 等于2时,根据前面提的条件两片必然是好芯片,任取一片即可。
2、芯片数 n 等于3时 (两好一坏),任取两片芯片做测试,若是情况2或3,没测的那个芯片必定时好芯片;若是其他情况,两个被测芯片必然是好芯片,则任取一片被测芯片即可。
3、芯片数 n 大于3时,分为两种情形i。n 为偶数时,芯片两两测试比较,在结果为情况1中取出一片另放,以便后续继续比较,若结果是情况2或3或4的都舍去(就是上面的淘汰规则)。n 为奇数时,取出一片芯片,然后将该芯片和其余的芯片进行一一比较,若比较结果为情况1的次数
>
n
2
> \frac n 2
>2n,则该芯片为好芯片,反之则为坏芯片,将坏芯片删除后;(此时芯片数为偶数) 接着又回到上面说的 n 为偶数的情形。
三、算法代码
C语言:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//建立测试函数,参数iA表示主动测试芯片, iB表示被测芯片.返回值为被测芯片的测试值
//值为1时表示好芯片,为0时表示坏芯片.
int X_test(int iA,int iB)
{
if(iA==1)
return iB;
return rand()%2;
}
int test(int AB[],int n)
{
int i, k,dM,iBack[n],iTmp,iC;//iBack保存AB数组中对应的编号
k=n;
for(i=0;i<n;i++)
iBack[i]=i;
while(k>3)
{
iC=0;
dM=k/2;
if(dM*2<k)
{//k为奇数,最后未分组的芯片被所有芯片测试1次
iTmp=0;
for(i=0;i<k-1;i++)
{
if(X_test(AB[iBack[i]],AB[iBack[k-1]]))
iTmp++;
}
if(iTmp>=dM)
return iBack[k-1];
}
for(i=0;i<dM;i++)
{
if(X_test(AB[iBack[2*i]],AB[iBack[2*i+1]])&&X_test(AB[iBack[2*i+1]],AB[iBack[2*i]]))
{
iTmp=iBack[2*i+rand()%2];
iBack[iC]=iTmp;
iC++;
}
}
k=iC;
}
if(k==3)
if(!X_test(AB[iBack[0]],AB[iBack[1]])||!X_test(AB[iBack[1]],AB[iBack[0]]))
return iBack[2];
return iBack[rand()%2];
if(k==2)
return iBack[rand()%2];
return iBack[0];
}
void main()
{
int ABc[17]={1,0,0,1,1,1,0,0,1,1,1,1,0,1,0,0,0};//17
srand(time(NULL));
int iN,I1,I2;
iN=test(ABc,17);
printf("最少的测试次数为:%d",iN);
}
需要转载请标明出处