题目

一个袋子里有30个银币,其中一枚是假币,并且假币和真币一模一样,肉眼很难分辨,目前只知道假币比真币重量轻一点。请问,如何区分出假币?

分析

首先为每个银币编号,然后将所有的银币等分为两份,放在天平的两边。这样就将区分30个银币的问题变为区别两堆银币的问题。

因为假币分量较轻,因此天平较轻的一侧中一定包含假币。再将较轻的一侧中银币等分为两份,重复上述做法。直到剩下两枚银币,便可用天平直接找出假银币。类似于二分法

代码

由于这个是自己做的一个练习题,没有使用OJ判题,所以自己利用随机数生成银币的重量和假币相关信息

#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std; 

void generate_seq(int coin[])
{
    srand(time(0));
    int coin_weight = rand() % 100;
    int fake_weight = rand() % coin_weight;
    int fake_add = rand() % 30;
    for (int i = 1; i <= 30; i++)
    {
        if (i == fake_add)
            coin[i] = fake_weight;
        else
            coin[i] = coin_weight;
    }
    cout << "fake_add=" << fake_add << endl; 
    cout << "fake_weight=" << fake_weight << endl; 
}

void show_seq(int coin[])
{
    for (int i = 1; i <= 30; i++)
    {
        cout << coin[i] << " ";
    }
    cout << endl; 
}

int find_fake(int coin[], int begin, int end)
{ 
    if (begin == end)
        return begin;
    
    double mid = (begin + end) / 2; 
    int weight_a = 0, weight_b = 0;

    if ((end - begin + 1) % 2 == 0) //可等分
    {
        for (int i = begin; i <= (int)mid; i++)
            weight_a += coin[i];
        for (int i = (int)mid + 1; i <= end; i++)
            weight_b += coin[i];
        cout << begin << " " << end << " " << mid << endl;
        cout << weight_a << " " << weight_b << endl;

        if (weight_a < weight_b)
            find_fake(coin, begin, (int)mid); 
        else 
            find_fake(coin, (int)mid+1, end); 
    }else //不可等分,中间留一个mid
    {
        for (int i = begin; i < mid; i++)
            weight_a += coin[i];
        for (int i = mid + 1; i <= end; i++)
            weight_b += coin[i];
        cout << begin << " " << end << " " << mid << endl;
        cout << weight_a << " " << weight_b << endl;

        if (weight_a < weight_b)
            find_fake(coin, begin, (int)mid - 1);
        else if (weight_a > weight_b)
            find_fake(coin, (int)mid + 1, end);
        else    
            return mid; 
    }
    
}

int main()
{
    //产生随机数列
    int coin[31];
    generate_seq(coin); 

    //打印数列
    show_seq(coin); 

    //找
    int fake_add = find_fake(coin, 1, 30); 
    cout << "fake_add=" << fake_add << endl; 
    cout << "fake_weight=" << coin[fake_add] << endl;  
    return 0; 
}