寻找假币

一、问题描述

一个袋子里有若干硬币,其中一枚是假币,并且和假币和真币一模一样,目前只知道假币比真币轻一点。请问如何找到这枚假币?

二、算法分析

根据分治的策略,将硬币平分为两份(奇数个硬币取出中间的硬币后再平分),比较两边的重量之和的大小。左侧重,则假币在右半段,反之,假币在左半段(或者中间的假币),然后继续在有假币的半区查找,直到剩余两个硬币,比较大小后,返回假币的位置。


时间复杂度:O(logn)。

三、代码实现

#include <stdio.h>

#define MAXNUM 30

int FalseCoin(int coin[], int low, int high)
{
    // 两个硬币的比较
    if (low + 1 == high) {
        if (coin[low] < coin[high]) {
            return low + 1;
        }
        return high + 1;
    }
    
    int sum1 = 0, sum2 = 0, sum3 = 0;
    int mid = (low + high) >> 1;
    int i;
    
    // 偶数个硬币
    if ((high - low + 1) % 2 == 0 ) {
        
        // 左半段
        for (i = low; i <= mid; i++) {
            sum1 += coin[i];
        }
        // 右半段
        for (i = mid + 1; i <= high; i++) {
            sum2 += coin[i];
        }
        
        // 左侧重,则假币在右半段
        if (sum1 > sum2) {
            return FalseCoin(coin, mid + 1, high);;
        }
        // 右侧重,则假币在左半段
        else if (sum2 > sum1){
            return FalseCoin(coin, low, mid);;
        }
        else {
            printf("没有假币。输入的硬币重量有误!");
        }
    }
    // 奇数个硬币
    else {
        // 左半段,除去中间的一个硬币
        for (i = low; i <= mid - 1; i++) {
            sum1 += coin[i];
        }
        // 右半段,除去中间的一个硬币
        for (int i = mid + 1; i <= high; i++) {
            sum2 += coin[i];
        }
        
        sum3 = coin[mid];
        
        // 左侧重,则假币在右半段
        if (sum1 > sum2) {
            return FalseCoin(coin, mid + 1, high);
        }
        // 右侧重,则假币在左半段
        else if (sum2 > sum1){
            return FalseCoin(coin, low, mid - 1);
        }
        else {
            // 中间的是假币
            if (coin[mid] != coin[low]) {
                return mid + 1;
            }
            else {
                printf("没有假币。输入的硬币重量有误!");
            }
        }
    }
    return -1;
}

int main()
{
    int coin[] = { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 };

    int position = FalseCoin(coin, 0, 9);
    
    printf("假币在第 %d 个位置", position);

    return 0;
}

假币在第 4 个位置
原文地址:https://www.cnblogs.com/dins/p/looking-for-counterfeit.html