Python 之通过一个天平找出9个小球中唯一重量较轻的小球

哈哈,这个题和 Python 本身没什么关系哈,最主要的解题思路,用什么来实现倒是其次。我们可以看看,从非天才的普通人的视角来讲,这种题需要怎么解。

题目

题目大体是这样:你有一个不带刻度的天平,还有 9 个外观完全一致的小球(其中一个小球的重量比其他 8 个小球要轻)。问最少多少次称重可以找到这个重量不一样的小球?称重方案是什么?

分析

首先,有一个天平,虽然没有刻度(类似于尺规作图,所以有没有刻度不是最重要的),但是我们知道,天平的两边可以放东西,通过天平是否平衡可以知道两边物体的轻重。

还有就是要让称重次数最少,既然要称重次数最少,那最好对九个小球进行分组,然后进行称重。

分组特点

根据分析,我们可以总结出小球分组的特点。分组要尽量考虑已有唯一工具天平的特性,所以要使用天平进行称重的两组小球个数必须一致(尽量均分)。试想,如果称重的时候天平两边的小球个数不一致,称重结果也就没什么参考价值。

分组分球

1组(平凡分组):分成 1 组的话,天平就失效了(天平至少要两组才可以称重),所以用处不大,舍弃。

2组:如果分成 2 组,因为小球个数是奇数,则这 2 组小球的个数必然不可能一样,舍弃。

4组:在保持均分特点的情况下,分成 4 组的分发有 [2, 2, 2, 3] 和 [1, 1, 1, 6],对于其中的 [2, 2, 2] 和 [1, 1, 1] 分组的小球,至少要称重 2 次才能确定较轻的小球一定不在其中,再加上对剩下那组小球的二次分组和称重,称重次数肯定至少是 3 次。

5组:在保持均分特点的情况下,分成 5 组的分发有 [2, 2, 2, 2, 1] 和 [1, 1, 1, 1, 5],因为天平一次只能对其中的两组小球进行称重,包括涉及到二次分组的极限情况下,也至少要称重 3 次才能找到较轻的小球。

6组及以上:对于 6 组及以上的情况,因为分组的数目太多,也至少要对分组的小球称重 3 次及以上才可以一定找到较轻的小球。

3组:如果小球分成 3 组,按照均分的原则,分法就是 [3, 3, 3]。我们对其中两组小球进行称重。

第一次称重: 如果天平保持平衡,则说明较轻的小球在剩下那组;如果天平不平衡,则称重的两组小球,其中较轻的那组小球必然在天平中翘起。但是不管哪种情况,我们都可以将较轻的小球的范围限定在3组小球中的其中一组。

第二次称重: 第一次称重将较轻的小球限定在了其中一组中,也即将范围限定在3个小球以内。我们对较轻的那组小球,按照均分原则进行第二次分组。只能是分成 [1, 1, 1]。再对分组后的 3 个小球进行第二次称重。同上,如果天平保持平衡,则说明较轻的小球就是剩下那个;如果天平不平衡,则称重的两个小球,其中较轻的那个小球必然在天平中翘起。但是不管哪种情况,我们都可以在第二次称重将较轻的小球找到。

总的看来,分成三组的这种方式,可以最多称重两次,即可将较轻的那个小球找到。

实现

查找实现

前一段时间刚好学了下 Python 的新语法 match case,这次正好学以致用,熟悉一下。

python 复制代码
import random


# 生成初始的 9 个小球
def gen_init_balls():
    init_balls = [10 for i in range(8)]  # 初始的8个质量相同的球(假设重量为 10)
    light_ball = 8  # 较轻的那个球(假设重量为 8)
    random_index = random.randint(0, 9)
    init_balls.insert(random_index, light_ball)  # 随机放到 8 个球中
    return tuple(init_balls)


# 对分组的两组小球进行称重
def weigh_balls(group1, group2):
    print("开始对分组小球进程称重")
    sum1 = sum(group1)
    sum2 = sum(group2)
    diff = sum1 - sum2
    match diff:
        case _ if diff > 0:
            return 1
        case _ if diff == 0:
            return 0
        case _ if diff < 0:
            return -1


if __name__ == '__main__':
    # init_balls = (10, 10, 10, 8, 10, 10, 10, 10, 10)
    init_balls = gen_init_balls()
    print(init_balls)
    # 小球第一次分组
    group1 = init_balls[0:3]
    group2 = init_balls[3:6]
    group3 = init_balls[6:9]
    # 对分组后的其中两组进行称重
    weigh_result = weigh_balls(group1, group2)
    match weigh_result:
        # 如果 group1 和 group2 重量相等
        case 0:
            # 对 group3 进行二次分组
            index = 2
            group4 = group3[0:1]
            group5 = group3[1:2]
            group6 = group3[2:3]
        # 如果 group1 更重
        case 1:
            # 对 group2 进行二次分组
            index = 1
            group4 = group2[0:1]
            group5 = group2[1:2]
            group6 = group2[2:3]
        # 如果 group2 更重
        case _:
            # 对 group1 进行二次分组
            index = 0
            group4 = group1[0:1]
            group5 = group1[1:2]
            group6 = group1[2:3]
    # 对二次分组后的其中两组进行称重
    weigh_result = weigh_balls(group4, group5)
    match weigh_result:
        case 0:
            print(f"最轻的小球是第 {3 * index + 3} 个")
        case 1:
            print(f"最轻的小球是第 {3 * index + 2} 个")
        case _:
            print(f"最轻的小球是第 {3 * index + 1} 个")

运行示例

因每次生成的随机数不一样,所以每次的运行结果也会不一样。可以看出,查找总共对小球进行了 固定 2 次的称重。

python 复制代码
(10, 8, 10, 10, 10, 10, 10, 10, 10)
开始对分组小球进程称重
开始对分组小球进程称重
最轻的小球是第 2 个
相关推荐
知乎的哥廷根数学学派10 分钟前
基于生成对抗U-Net混合架构的隧道衬砌缺陷地质雷达数据智能反演与成像方法(以模拟信号为例,Pytorch)
开发语言·人工智能·pytorch·python·深度学习·机器学习
实心儿儿20 分钟前
Linux —— 基础开发工具5
linux·运维·算法
WangYaolove131431 分钟前
Python基于大数据的电影市场预测分析(源码+文档)
python·django·毕业设计·源码
知乎的哥廷根数学学派43 分钟前
基于自适应多尺度小波核编码与注意力增强的脉冲神经网络机械故障诊断(Pytorch)
人工智能·pytorch·python·深度学习·神经网络·机器学习
charlie1145141911 小时前
嵌入式的现代C++教程——constexpr与设计技巧
开发语言·c++·笔记·单片机·学习·算法·嵌入式
cnxy1882 小时前
Python爬虫进阶:反爬虫策略与Selenium自动化完整指南
爬虫·python·selenium
清木铎2 小时前
leetcode_day4_筑基期_《绝境求生》
算法
清木铎2 小时前
leetcode_day10_筑基期_《绝境求生》
算法
j_jiajia3 小时前
(一)人工智能算法之监督学习——KNN
人工智能·学习·算法
用户8356290780513 小时前
Python 实现 Excel 条件格式自动化
后端·python