12球称重问题思维分析(updated #1)

本文详细分析了12个球中找重量异常球的思维过程和解题策略。通过逐步拆解问题,从两球、三球的称重情况讨论,提出用标记法记录球的重量状态,最终确定使用信息获取最大化的原则解决12球问题,最多只需三次称重。

昨天又从某处看到了12球称重的问题,虽然之前有过解题的过程,但这次仍然费了不少时间才又找到解题方法。然后我又思考,从我看到问题,到得到解决方法,这是怎样的一个过程,怎样的思维想到了怎样一个方法,从而得到了怎样的一个结果。假如我能够把这个过程描述下来,那可谓对自己的思维过程有了一个很好的梳理,并且可以记录入自己的SOP;同时,也就更加真实地了解自己。而更为重要的是,可以将这种思维的过程,传播出去;从而不仅仅是知识得到延续,而更为重要的思维过程,也可以得到延续。

题目:12个球,外观(大小、色泽等)完全一致,其中,有十一个球的重量是一样的,另一个球的重量与其他球是不一致的。怎样用天平最多仅称重三次,找出那个重量不一致的球,并且还能确认这个球是较重还是较轻。

这个题的重点是不知道那个不一致的球是重了还是轻了。那假如是这个球是重的呢?

很多人的思路是,平分成两组,每组6个,进行称重。然后将重的一组再分组,每组3个,进行称重。最后,将重的一组(3个球)其中两个称重,若有一个重,则这个球是要找的球;若相等,则没有称重的这个球是要找的球。

但是这个过程是无法直接应用到要解决的问题上的。所以,只能换一个方向——简化。

两个球的情况:无法得知哪个球是要找的球。

三个球的情况:标记ABC,取AB进行称重,会有两种情况:

1,它们相等,那么C就是要找的球,称A和C

1.1 C>A,C较重。

1.2 C<A,C较轻

1.3 C=A,A=B=C,与前提矛盾,因此不可能出现。

2,它们不等,我们假设A>B,那么C是一颗正常的球。将A与C称重,

2.1相等,B球较轻,为要找的球。

2.2A>C,A球较重,为要找的球。

2.3A<C,那么C>A>B,与前提矛盾,因此不可能出现。

然后再回过头来,看上面的过程。你会发现什么,先想一想吧……

这其实是一个信息获取的过程,根据已知信息,通过操作,得到未知信息。如果我们一直测AB的话,即使测100遍也无法找到重量较轻或者较重的那个球。

可以通过一种标记来记录信息,这里球有正常,较轻和较重三种情况,可以用(+1,0,-1)来表示。当通过一次次的测量,为各个球标上(+1,0,-1)三种状态,并最终有且仅有一个球的状态为+1或者-1,就可以确定,这个状态为+1或者-1的球为要找的较重或者较轻的球。为上述操作过程分别标记信息含量值

1,它们相等,那么C就是要找的球[A0,B0,C]

称A和C

1.1 A<C,C重[A0,B0,C+]

1.2 A>C,C轻[A0,B0,C-]

1.3 C=A,A=B=C,与前提矛盾,因此不可能出现。

2,它们不等,我们假设A>B,那么C是一颗正常的球。[A+,B-,C0]

将A和C

2.1 A=C,B轻[A0,B-,C0]

2.2 A>C,A重。可由A>C和前提得知B=C,因此[A+,B0,C0]

2.3 A<C,那么C>A>B,与前提矛盾,因此不可能出现。

那么,总结一下整个过程,就是将球分为较重、较轻(标记+-),并通过和标准球(标记0)的比较,来得知是否为重球(不是重球,则与之相比较的球是轻球)或者轻球。

再来分析一下标记的信息值,0表示为标准球,含有确切含义,而+和-在不唯一的情况下,只能表示可能较重,但其实并不重,按其信息值排序的话:0>(+或-)>没有标记,我们的目的是在每次称重的过程中,使获得的信息值最大化。

12球的过程

6:6称重,只能将6个球标记为+,另6个球标记为-,无法得到0的标记

而4:4称重,至少可以将4个球标记为0(其实,有两种可能,一是8个0,另一种是4个+,4个-,4个0)

(未完待续)
4:4称重
1.  两边相平
     1~8标记为0
     将9,10放左边,11和1放右边,称重
1.1 左边重
     9,10:+
     11:-
     12:0
     对9,10进行称重,便可得到结果
1.1.1 9=10,则9,10:0,11为较轻的球
1.1.2 9>10,则9为较重的球
1.1.3 9<10,则10为较重的球

1.2 右边重
     9,10:-
     11:+
     12:0
     同1.1剩余部分

1.3 同样重
      则9,10,11标记为0,取1和12称重,因为1是标准球,根据天平状态,可以得出12球是轻还是重

2.  左边重
     1~4:+
     5~8:-
     9~12:0
在C语言中,我们可以使用递归或者循环的方式模拟这个过程。这里以递归为例来展示解决方案: ```c #include <stdio.h> int findLightBall(int balls[], int n, int weighings) { // 第一次称量 if (weighings == 0 || n <= 3) { for (int i = 0; i < n; i++) { if (balls[i] < balls[0]) return i + 1; } return 1; // 假设第一个是最轻的,因为没有其他选择 } // 分割成三份 int mid = n / 3; int left[3], right[3]; for (int i = 0; i < mid; i++) { left[i] = balls[i]; } for (int i = mid; i < 2 * mid; i++) { right[i - mid] = balls[i]; } // 第二次称量 int lighterSide; if (weigh(left, right, 1)) { // 左边重 lighterSide = 1; } else { // 右边重 lighterSide = 2; } // 第三次称量 int lightBallIndex = findLightBall(weighs[left[mid]], 3, weighings - 1); if (lighterSide == 1) return lightBallIndex + 1; else return lightBallIndex + mid + 1; } // 递归函数,传入已分割的数组和当前层数 int weighs(int arr[], int n, int depth) { // 实际测量,这里是假定arr[n-1]是最轻的 if (depth == 0) return 1; // 表示左边较轻 return n % 2 ? 0 : 1; // 假设偶数次称量时右边是轻 } int main() { int balls[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int n = sizeof(balls) / sizeof(balls[0]); printf("The index of the light ball is: %d\n", findLightBall(balls, n, 3)); return 0; } ``` 这个程序假设每次称重的结果都是随机的,实际上需要替换为实际的比较操作。注意,这是一个简化的例子,实际应用中需要处理更多的边界条件和错误检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值