银币次品求解问题---二分法和三分法比较(python代码)

N块银币中有一块不合格,已知不合格的银币比正常银币重。现有一台天平,请利用它找出不合格的银币,并且要求使用天平的次数最少。




def sum(left,right):
    num=0
    for i in range(left,right+1):
        num=list1[i]+num

    return num

def search(left,right):
    mid=(left+right)//2
    global f
    if left==right-1:

        f = f + 1
        if list1[left]>list1[right]:

            return left
        else:return right

    if (right-left)%2==0:#说明是奇数
        f = f + 1
        if sum(left,mid-1)>sum(mid+1,right):


            return search(left,mid-1)
        elif sum(left,mid-1)<sum(mid+1,right):


            return search(mid+1,right)
        else :return mid

    else :#说明是偶数
        f = f + 1
        if sum(left,mid)>sum(mid+1,right):

            return search(left,mid)
        else :

            return search(mid+1,right)

if __name__ == '__main__':
    N = int(input("请输入银币总数:"))
    s = int(input("请输入不合格银币所在位置:"))
    left = 1
    right = N
    f = 0

    list1 = [1 for i in range(N + 1)]
    list1[s] = 2
    flag=search(1,N)

    print(f"不合格银币位置:{flag}")
    print(f"比较次数:{f}")
















下面是使用三分法的代码,最后比较一下使用二分和三分的优缺点。

def sum(left,right):
    num=0
    for i in range(left,right+1):
        num=list1[i]+num

    return num

def search(left,right):
    mid=(right-left+1)//3
    k=(right-left+1)%3
    global f

    if left==right:
        f=f+1
        return left
    elif left==right-1:
        f=f+1
        if list1[left]>list1[right]:
            return left
        else :return right

    f = f + 1
    if sum(left,left+mid-1)>sum(left+mid,left+mid*2-1):

        return search(left,left+mid-1)
    elif sum(left,left+mid-1)<sum(left+mid,left+mid*2-1):

        return search(left+mid,left+mid*2-1)
    elif sum(left+mid*2,left+mid*3-1)>sum(left,left+mid-1):

        return search(left+mid*2,left+mid*3-1)
    else:
        if k==1:
            return right
        elif k==2:
            f=f+1
            if list1[right-1]>list1[right]:
                return right-1
            else :return right













if __name__ == '__main__':
    N = int(input("请输入银币总数:"))
    s = int(input("请输入不合格银币所在位置:"))
    left = 1
    right = N
    f = 0

    list1 = [1 for i in range(N + 1)]
    list1[s] = 2
    flag=search(1,N)

    print(f"不合格银币位置:{flag}")
    print(f"比较次数:{f}")

粗略的发现,三分法在银币总数大时的比较次数更少,更适合。

在C语言中解决这个问题,可以采用分治法的思想,尤其是二分查找策略,称为“称量法”。假设我们有N个银币,为了找到那块较重的,我们可以按照以下步骤进行: 1. **第一步** (基础情况):如果只有两个银币,直接进行一次称量即可判断出哪一块更重。 2. **第二步** (递归步骤):如果有更多的银币(比如N=4),将它们分为两组,每组两个。首先比较这两组,如果天平平衡,说明不合格的银币在未称量的那一组;如果不平衡,不合格的银币一定在较重的一侧。 3. **第三步**:对确定的那一组继续二分查找。每次将剩余的银币分成两半,直到只剩下一个,这个就是不合格的银币,因为如果它是正常的,之前应该会被平均分配到天平两侧。 **最少的天平操作次数**: - 对于N个银币,最坏的情况下需要进行log2(N)+1次称量,因为每次称量都能排除一半的选项。 **算法伪代码举例**: ```c int find_heavyCoin(int coins[], int n, int scale) { if (n == 1) return 0; // 单个检查 // 如果偶数个硬币,先除以2,否则分成两个相等的部分 if (n % 2 == 0) return find_heavyCoin(coins, n / 2, scale + 1); // 初始称量,得到较重那一边 int heavy = compareCoins(coins, n / 2, n / 2, scale); if (heavy == -1) // 两边不平衡,不合格在剩下的部分 return find_heavyCoin(coins + n / 2, n / 2, scale + 1); else return find_heavyCoin(coins, n / 2, scale); // 不合格在前半部分 } // 比较两个子集,返回+1、-1表示较重那一边,0表示平衡 int compareCoins(int coins[], int first, int second, int scale) { // ... 实现具体的称量函数 ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值