在n(n≥3)枚硬币中混有一枚不合格硬币(重量过轻或过重未知),如果只有一架天平可以用来称重且称重硬币数量没有限制,设计一个算法找出这枚不合格硬币,使得称重次数最少。
二分法:
将这n个硬币分成两等份,然后放到天平的两端,则假币在较轻的那一端;
然后将较轻的那一端的硬币再分成2等份,然后再放到天平的两端进行比较,假币还是在较轻的那一段;
直到最后只剩下两个硬币了,分别放到天平的两端,轻的哪一个就是假币。
当然,最后也可能剩下3个硬币,我们可以将这3个硬币中任意拿出来一个,然后将剩下的两个放到天平的两端,如果天平是平的,则说明拿出来的那个硬币就是假币;
如果天平不是平的,则轻的那一端是假币。
代码实现:(时间复杂度:O(log(2)(n))
#include<iostream>
using namespace std;
int sum(int a[],int left,int right)
{
int sum=0;
for(int i=left;i<=right;i++) sum+=a[i];
return sum;
}
int FindCorn(int a[], int left, int right)
{
int sum1,sum2,sum3;
sum1=sum2=sum3=0;
if(left+1==right)
{
if(a[left]<a[right]) return left;
else return right;
}
if((right-left+1)%2==0)
{
sum1=sum(a,left,left+(right-left)/2);
sum2=sum(a,left+(right-left)/2+1,right);
if(sum1>sum2) return FindCorn(a, left+(right-left)/2+1, right);
else if(sum1<sum2) return FindCorn(a, left, left+(right-left)/2);
}
else
{
sum1=sum(a,left,left+(right-left)/2);
sum2=sum(a,left+(right-left)/2+1,right);
sum3=a[left+(right-left)/2];
if(sum1>sum2) return FindCorn(a ,left+(right-left)/2+1, right);
if(sum1+sum3==sum2+sum3) return left+(right-left)/2+1;
}
}
int main()
{
int a[]={2, 2, 2, 2, 2, 2, 1, 2,2};
int left=0,right=0;
for(int i=1;a[i]!='\0';i++)
right++;
cout<<FindCorn(a,left,right)<<endl;
return 0;
}
三分法:
将n枚硬币分成三组,前两组有组硬币,其余的硬币作为第三组;
将前两组硬币放到天平上,如果它们的重量相同,则假币一定在第三组中,用同样的方法对第三组进行处理;
如果前两组的重量不同,则假币一定在较轻的那一组中,用同样的方法对较轻的那组硬币进行处理。
代码实现:(时间复杂度:O(log(3)(n)))
#include<iostream>
using namespace std;
int sum(int a[],int left,int right)
{
int sum=0;
for(int i= left;i<=right;i++) sum+=a[i];
return sum;
}
int FindCorn(int a[],int left,int right)
{
int n=right-left+1;
int x;
if(n==1) return left;
if(n%3==0) x=n/3;
else
{
x=n/3+1;
return FindCorn(a,left+1,right);
}
int mid1=left+x-1;
int mid2=mid1+x;
if(sum(a,left,mid1)==sum(a,mid1+1,mid2))
return FindCorn(a,mid2+1,right);
else if(sum(a,left,mid1) < sum(a,mid1+1,mid2))
return FindCorn(a,left,mid1);
else
return FindCorn(a,mid1+1,mid2);
}
int main()
{
int a[]={2, 2, 2, 2, 2, 2, 1, 2};
int left=0,right=0;
for(int i=1;a[i]!='\0';i++)
right++;
cout<<FindCorn(a,left,right)<<endl;
return 0;
}