前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >分治应用--万里挑一 找假硬币

分治应用--万里挑一 找假硬币

作者头像
Michael阿明
发布2021-02-20 10:48:59
发布2021-02-20 10:48:59
51800
代码可运行
举报
运行总次数:0
代码可运行

1. 问题描述

n 个硬币中有1枚是假币,真假币唯一的区别是假币重量轻,如何快速找出假币

2. 解题思路

  • 暴力做法,一个一个的称重,O(n)复杂度
  • 分治思路
  1. 将硬币等分成两份,若为奇数,多出一枚,放在天平两边
  2. 轻的一边包含假币,若相等,则假币是多出的那一枚
  3. 对轻的一边继续上述操作,直到找出假币 复杂度O(log n)

3. 代码实现

代码语言:javascript
代码运行次数:0
复制
/**
 * @description: n 个硬币中有1枚是假币,假币重量轻,如何快速找出假币
 * @author: michael ming
 * @date: 2019/7/6 20:37
 * @modified by: 
 */
#include <iostream>
#include <ctime>
#include <random>
using namespace std;
int findcoin(int *weight, int left, int right, int &weightimes)
{
    if(left+1 == right)//只有2枚硬币
    {
        weightimes++;//称重比较一次
        if(weight[left] < weight[right])
            return left;//返回重量小的位置
        else
            return right;
    }
    int i, mid, weightsumL, weightsumR;
    weightsumL = weightsumR = 0;
    mid = left + (right-left)/2;
    if((right-left+1)%2 == 0)//偶数枚银币
    {
        weightimes++;
        for(i = left; i <= mid; ++i)
            weightsumL += weight[i];//计算左边重量(计算机没有天平,只能一个个加)
        for(i = mid+1; i <= right; ++i)
            weightsumR += weight[i];//右边重量
        if(weightsumL > weightsumR)//左边重,假币在右边
            return findcoin(weight,mid+1,right,weightimes);
        else if(weightsumL < weightsumR)//假币在左边
            return findcoin(weight,left,mid,weightimes);
        else//假币不在两边(偶数枚银币)
            ;//什么都不做,不必再找了
    }
    else//奇数枚硬币
    {
        weightimes++;
        for(i = left; i <= mid-1; ++i)
            weightsumL += weight[i];//计算左边重量
        for(i = mid+1; i <= right; ++i)
            weightsumR += weight[i];//右边重量
        if(weightsumL > weightsumR)//左边重,假币在右边
            return findcoin(weight,mid+1,right,weightimes);
        else if(weightsumL < weightsumR)//假币在左边
            return findcoin(weight,left,mid-1,weightimes);
        else//两边相等(奇数枚硬币),剩余的那个是假币
            return mid;
    }
}
int main()
{
    srand(unsigned(time(0)));
    int num, i, weightimes = 0;
    cout << "请输入硬币总个数:";
    cin >> num;
    const int coinNum = num;
    int *weight = new int [coinNum];
    for(i = 0; i < coinNum; ++i)
    {
        weight[i] = 10;
    }
    i = rand()%num;
    weight[i] = 9;  //随机生成假币
    for(i = 0; i < coinNum; ++i)//打印硬币信息
    {
        cout << i + 1 << " 硬币重量: " << weight[i] << endl;
    }
    cout << "假硬币是第" << findcoin(weight,0,coinNum-1,weightimes)+1 << "个。" << endl;
    cout << "共称了" << weightimes << "次,找到假币。";
    delete[]weight;
    return 0;
}

输入 2500枚、5001枚,100万枚,最多需要 log2n 向上取整次就能找到。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/07/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 问题描述
  • 2. 解题思路
  • 3. 代码实现
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档