分治算法:芯片检测问题

一、问题描述

有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报告结论
1B是好的A是好的A,B都好或A,B都坏
2B是好的A是坏的至少1片是坏的
3B是坏的A是好的至少1片是坏的
4B是坏的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);
}

需要转载请标明出处

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值