分治法解决硬币问题(二分法/三分法)(C++实现)

在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;
}

  • 2
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值