称硬币问题-Python

称硬币问题-Python:

一. 问题描述
现在有27枚硬币,其中有一枚假币,假币跟真币长得一摸一样,但是稍微重一些。摆在桌上有一个称重天平,要求用最小的次数找出假币,并写出算法代码。

二. 解题思路
首先,思考一下这个问题的解法,很多人开始想到的都说对开。就是把硬币分成两份,比如假如我们有9个硬币,每4一份,分成4,4,1三份,再对前两份进行称重。那么可能有3个结果:
1).两份完全相等,剩下的1个就是假币
2).第一组更重,然后继续二分称重
3).第二组更重,然后继续类似上面第二种情况进行称重

我们需要3次才能找到,这个是不是最优的解法呢,显然不是,何况现在的题目是27枚硬币!

三. 更优解法:
应该采用的是分而治之的方法,我们还是先拿简单的9枚举例,把9枚硬币分成3份,3,3,3,然后称重,应该是3种结果:
1).第一组和第二组一样重,那么假的在第三组里面,再称一次即可找出;
2).第一组更重,那么假的在第一组,再称一次即可;
3).第二组更重,那么假的在第二组,再称一次即可;

这个的算法,看起来更简介,大概需要2次,如果是27枚,只要多分一次9,9,9 ,最后3次即可。

四. 代码实现需要解决的三个问题:
第一,把硬币分3组;
第二,把分组的硬币称重;
第三,遍历寻找最重的里面的假币

  • 1).分组问题
    拿到一串硬币,我们需要分成3等份,直接用切片把列表切割一下即可。
def fenzu (coins):
    length=len(coins)
    group_a=coins[0 : length//3]
    group_b=coins[length//3 : length//3*2]
    group_c=coins[length//3*2 : length]
    return group_a,group_b,group_c
  • 2).硬币称重
    两种硬币进行称重对比代码实现
#称重
def chengzhong (group_a,group_b):
    if sum(group_a) > sum(group_b):
        result=('left')
    elif sum(group_a) < sum(group_b):
        result=('right')
    else:
        result =('equal')
    return result
  • 3).寻找假币
    这个里面分两步走,第一步先寻找假币,就是给你3组,进行判断。
    如果第一组和第二组对比称重,左边重,那么假币就在第一组中;
    如果第二组重,就是右边重,那么假币就在第二组重;
    如果都不是,假币在第三组中。
#找假币
def find_fake(group_a,group_b,group_c):
    res=chengzhong (group_a,group_b)
    if res=='left':
        return group_a
    elif res=='right':
        return group_b
    elif res=='equal':
        return group_c

  • 4).遍历寻找
    times 用于记录搜索的次数,而search_list是一个可变的列表,每次称重完了之后,它会变成三分之一的长度,不断的缩小,直到搜索结束。
#遍历寻找
def bianlifind(coins):
    times=0
    search_list=coins
    while len(search_list)> 1:
        print('search_list',search_list)
        g1,g2,g3=fenzu(search_list)
        search_list=find_fake(g1,g2,g3)
        times += 1
    fake=search_list[0]

    print(f'错误的硬币在第{fake}组')
    print(f'称重次数{times}')
coins=[1,1,1,2,1,1,1,1,1]
bianlifind(coins)

五. 总结和反思:
在以上的代码中输入的硬币个数是在整除3的情况下实现的。
在实际操作中:
当硬币个数不能整除3时,应该怎么做?

六. 扩展题目:
在n枚外观相同的硬币中,有一枚是假币,并且已知假币与真币的重量不同,但不知道假币与真币相比较轻还是较重。可以通过一架天平来任意比较两组硬币,设计一个高效的算法来检测这枚假币.

七. 思路:
将硬币分为3堆,则每堆的硬币数量为 n/3 ,但是这是在 n%3==0 的情况下才能成立,所以我们将 n 枚硬币分为 3 堆加 1 堆 余数堆(余数堆可能为0),则可分为如下(n-n%3)/3, (n-n%3)/3, (n-n%3)/3, n%3。
如下分组:
a堆: (n-n%3)/3
b堆: (n-n%3)/3
c堆: (n-n%3)/3
d(余数堆): n%3

八、逻辑过程:

  1. 判断n中的硬币数量,如果n>2则执行2,否则执行5.
  2. 将n分为上图的四堆,拿 a 和 b 比较,如果 a == b ,则 假币在 c 或 d 中。否则假币在 a 或 b 中。
  3. 如果 a == b,则拿 a 和 c 比较。如果 a == c,则假币在d(余数堆)中。将 d 再次 执行流程1,并且n=n%3。如果不等,则假币在 c 中,将 c 再次 执行流程1,并且n=(n-n%3)/3。
  4. 如果 a != b,则拿 a 和 c 比较。如果 a == c,则假币在b中,将 b 再次 执行流程1,并且n=(n-n%3)/3。如果不等,则假币在 a 中,将 a 再次 执行流程 1,并且n=(n-n%3)/3。
  5. 如果n==2,则将两枚硬币进行比较找出假币。
  6. 如果n==1,则该硬币就是假币,输出结果结束。

九.逻辑图:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值