有12个球,其中一个的重量跟其他的不一样,给你一个天平,没有砝码,让你称三次,找出这个重量不一样的球

2021.04 最近看到《暗时间》里有个章节讲到这个问题,里面还提到了一般性的解题思路,而不是只给出结果。所以回来记录一下,链接:称球
文章所讲的基本思路是:
先举个二分查找的例子,二分查找每次都是从中间分割,目标数有两种可能:①在左边,②在右边。二分查找是在中间分割,这就使两种可能出现的概率一样,从而使最坏查找时间最少。(同样类似的情况还有:将一个正整数,分成两个正整数之和,求这两个正整数乘积最大,也是对半分的情况)
文中所提的想法是在一次操作后使所有可能的结果都等概率出现,这样会使最坏情况下最好(引用其中一句话:让未知世界无机可乘)
题目分析:
每个球有三种可能(天平输出的结果):①重(左倾,+),②正常(平衡),③轻(右倾,-),我们所要做的是一次操作后使三种可能的概率相等。
对于题目所问的找出12个球中那个不一样的球,可以是第i个球,它可以重,也可以是轻。共12*2=24种情况。一次操作留下1/3的情况,二次留下1/9,三次留下1/27,一共24种,因此3次就够。链接中有个图,比较清晰。

以下部分转自:https://www.zybang.com/question/c7821f9ffc2657784b9a93dcdd407be7.html
需要称3次,才能保证找出来
------------------第一次-------------------
天平两边各放4个称,结果有两种:
一:不平衡,将重的一边4个标记为:重1;重2,重3,重4;轻的一边标记为:轻1,轻2,轻3,轻4;没称的标记为好1,好2;好3,好4
二: 平衡 将没称的标记为:次1,次2,次3,次4,天平上的都是好的

--------------第二次称(情况二)----------------------
将次1和次2称,平衡则次3或次4有问题
不平衡轻的标记为轻,重的标记为重
----------------第三次称(情况二)---------------
如果次3或次4有问题,将次3跟一个好的称,平衡,次4是要找的,不平衡,次3是要找的
如果次1和次2有问题,将重的与好的称
平衡,轻的是要找的,不平衡,重的是要找的


---------------------第二次称(情况一)-------------
天平一边放重1,重2,重3,轻4,一边放重4,好1,好2,好3
出现三种结果:
A:平衡:说明轻1,轻2,轻3三个当中有一个轻了
B:重1,重2,重3,轻4,这边重了: 说明肯定是重1,重2,重3三个当中有一个重了
C:重4,好1,好2,好3这边重了:说明要么是重4重了,要么是轻4轻了

-----------------第三次称(情况一)---------------
如果第二次出现的情况是A:
轻1,轻2称------如果平衡轻3轻了,如果不平衡,轻的那边那个轻了,是要找的球

如果第二次出现的情况是B:
重1,重2称------如果平衡重3重了,如果不平衡,重的那边那袋重了,是要找的球

如果第二次出现的情况是C:
轻4与好1称,如果平衡,重4重了,如果不平衡,轻4轻了

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这个问题可以用天平分治法来解决,具体步骤如下: 1. 将铅分成三组,每组放在天平两端进行量,找出重量较轻的一组。 2. 将较轻的一组铅继续分成三组,每组放在天平两端进行量,找出重量较轻的一组。 3. 将重量较轻的那组铅继续分成三组,每组放在天平两端进行量,找出重量较轻的一组。 4. 现在剩下的那组铅中就只有一个了,它就是三次量中被出来的轻的那个铅。 下面是用 C 语言实现这个算法的代码: ```c #include <stdio.h> int findFakeBall(int balls[], int start, int end) { if (start >= end) { return start; } int groupSize = (end - start + 1) / 3; int left = start, right = end; while (left < right) { int mid = (left + right) / 2; int sumLeft = 0, sumRight = 0; for (int i = left; i <= mid; i++) { sumLeft += balls[i]; } for (int i = mid + 1; i <= right; i++) { sumRight += balls[i]; } if (sumLeft < sumRight) { right = mid; } else { left = mid + 1; } } return findFakeBall(balls, start + groupSize, start + groupSize * 2 - 1); } int main() { int balls[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; int fakeBallIndex = findFakeBall(balls, 0, 9); printf("The fake ball is at index %d.\n", fakeBallIndex); return 0; } ``` 在这个代码中,findFakeBall 函数接收一个整型数组和两个整数参数 start 和 end,表示要在数组的 start 到 end 范围内查找假的索引。函数首先计算出每组铅的大小 groupSize,然后不断进行二分查找,将铅分成左右两组,并且计算出它们的重量。如果左侧的铅更轻,则继续在左侧进行查找;否则继续在右侧进行查找。最终,当只剩下一个时,它就是假的索引。 在上面的代码中,我们假定假重量是 0,而其他铅重量是 1。这样,我们只需要比较铅的数量,而不需要比较它们的重量。实际上,我们也可以假定假重量是任何一个不同于其他铅的值,然后通过比较重量来找到假

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值