Python解决12小球问题
三进制
12小球问题就是说有12个一模一样的小球,外表看不出区别,但是其中有且仅有一个小球是坏球,它比其他球可能重一点,也可能轻一点。给你一架天平,请只称三次就找到这个小球。上一篇博客已经说明了解这个问题的手工解,这次我们试图编写一个计算机算法来解决这个问题,难度显然要大多了。
解决这个问题之前,我们先来谈谈数的进制。为什么人类习惯使用十进制呢?因为人的两只手恰好有十根手指头,十进制计数方便。如果外星人有八个手指头,那他们极有可能常用的是八进制而不是我们认为理所当然的十进制。计算机中主要使用的是二进制,为什么选择二进制?因为绝大多数电子元器件的状态有两种:接通或关闭、电流高或低、磁性有或无。如果外星人的元器件的状态有三种的话我相信他们的计算机可能会使用三进制。
所以二进制也好,十进制也好,八进制也好,甚至三进制也好,本身并无孰优孰劣。计数和计算的能力也是相同的(如果你愿意甚至用一进制也行)。差别仅在于用起来是否方便。比如中国的算盘就是五进制的。在计算机发明以前,算盘是世界上最快的计算工具之一。直到进入21世纪,在中国的一些企事业单位的财务部门里仍能看到算盘的身影。你能说五进制的计算能力就差了吗?
作者前面写过一篇讲猜姓氏问题的博客,一个姓氏在或者不在纸上构成了姓氏的一个二进制编码。而12个小球问题中,天平有三个可能的状态:左边低右边高、左边高右边低或者平衡。这就提示了我们是否可以用三进制帮助我们解决这个困难的12小球问题呢?
小球的三进制编码
答案是肯定的。我们可以用若干位三进制编码给所有小球编码。比如,我们不妨把一号球编码为“001”。这个编码是什么意思呢?我们可以这样解释:3位编码表示我们一共称了3次天平。每一位的编码可以取值0、1或者2,其含义是:
1:表示左边低右边高。
2:表示左边高右边低。
0:表示天平平衡。
则一号球的编码“001”的含义是:如果一号球是坏球的话,三次称天平的结果分别是:
平衡(0)、平衡(0)、左边低(1)
这说明,作为坏球,一号球没有参与第一次和第二次称天平,但参与了第三次称天平。这很好理解吧?如果一个小球的编码是“122”,这说明,如果该球是坏球的话,它参与了三次称天平,并且天平分别呈现:左低(1)、右低(2)和右低(2)。
小球应放在天平的哪一端?
编码“001”说明了当前小球仅参与了第三次称天平,并且天平左边低。但是该编码并没有说明在第三次称天平时一号球放在了天平的哪一端。假设数字“1”意味着小球是放在天平左边的。现在天平左边低,这就说明,一号球是个重球。
作为一个坏球,如果一号球是个轻球,这意味着第三次称天平的结果是右边低。所以,一号球实际有两个编码,“001”是它作为重球的编码,“002”是它作为轻球的编码。
同一个小球的轻重两个编码是有联系的。比如,假设一个小球作为轻球的编码是“102”,则它作为重球的编码必然是“201”。即同一个小球轻重两个编码在同一位上的值之间具有互补关系。如果一个球的轻球编码第一位是“1”的话,则它的重球编码的第一位必然是“2”。反之亦然。只有当小球的轻球编码在某个位置上的值是“0”时,它的重球编码在同一个位置处的值必然也是“0”
这是因为小球只要作为坏球参与了某次称天平,并且固定放在某一边,则作为轻球导致天平呈现的状态必然与作为重球导致天平所呈现的状态互补。
小球的初步编码
综上所述,我们为12个小球进行初步编码。步骤是这样的:按三进制从001、002、010、011、012、020......的次序依次给每个小球轻重两种情况进行编码。比如:001给1号重球,则1号轻球的编码必然是002。接着010给2号重球,则2号轻球的编码必然是020。接下来011给3号重球,3号轻球编码必然是022。以此类推,给出所有小球的初步编码如下:
小球 |
重 |
轻 |
1 |
001 |
002 |
2 |
010 |
020 |
3 |
011 |
022 |
4 |
012 |
021 |
5 |
100 |
200 |
6 |
101 |
202 |
7 |
102 |
201 |
8 |
110 |
220 |
9 |
111 |
222 |
10 |
112 |
221 |
11 |
120 |
210 |
12 |
121 |
212 |
重码
在上述编码中,由于同一个小球的轻重两个编码是互补的,所以我们只用看一种编码即可。下面我们仅关注所有小球的重球编码(简称重码)。纵向地看各小球的重码,每一列代表本次称天平要用到哪些小球。其中“0”表示对应的小球没有出现,“1”表示该小球出现在天平的左边,“2”表示它出现在右边。
所以,从左往右,纵向地看每一个小球的编码,我们得出结论:第一次称天平时,左边是5号、6号、...、12号共8个小球,右边是0个小球!显然这是不合理的。每次称天平,两边应该有相同数量的小球,否则无论天平出现什么状态都不能说明任何问题。
优化三进制编码
解决上述小球数量不匹配问题的办法就是交换部分小球的轻重编码,使得每次称天平时两边放上相同数量的小球。同一个小球轻重编码交换会不会影响最终的判断?不会。假设某小球的重码是102(轻码必然是201),这意味着第一次称天平时该小球应该出现在天平的左边,这样才能保证第一次称天平出现左边低的状态(即状态“1”)。现在交换轻重码,重码变成了201,其中第一位的编码“2”意味着小球应该放在右边。重球在右边,当然会导致天平出现状态“2”(即右边低),天平的状态与小球的编码一致。所以交换小球的轻重码完全没有问题。
下面统计一下三次称天平左右两边的小球数量:
编码 |
第一次称 |
第二次称 |
第三次称 |
|
左边 |
“1” |
8 |
6 |
5 |
右边 |
“2” |
0 |
2 |
3 |
根据这个统计表,在第一次称天平时左右两边的小球数量分别是8和0 。这意味着我们应该交换四个以“1”打头的编码。假设这四个小球分别是W、X、Y、Z。
这种交换必然会影响第二次和第三次称时天平左右两边小球数量。上面统计表告诉我们第二次称球时的左右小球数量分别是6和2,也就是说需要交换两个编码。所以W、X、Y、Z中必然有两个小球的重码的第二位是“0”,另外两个小球的重码的第二位是“1”。假设W和X的第二位是“0”,Y、Z的第二位是“1”。也就是说,
W和X的重球编码形如10*
Y和Z的重球编码形如11*
其中*表示0、1或者2。
第三次称天平时左右两边小球的数量是5和3。我们可以令W和X的第三位互补,Y和Z的重码的第三位分别是“0”和“1”。反之亦然。
综上所述,W、X、Y、Z的重码分别是101、102、110和111。我们只需交换这四个小球的轻重编码即可。最终,我们得到如下所示的优化三进制编码:
12小球的优化三进制编码
小球 |
重 |
轻 |
1 |
001 |
002 |
2 |
010 |
020 |
3 |
011 |
022 |
4 |
012 |
021 |
5 |
100 |
200 |
6 |
202 |
101 |
7 |
201 |
102 |
8 |
220 |
110 |
9 |
222 |
111 |
10 |
112 |
221 |
11 |
120 |
210 |
12 |
121 |
212 |
其中黑体字部分就是交换过的编码。当然你也可以交换100、101、111和112的轻重码,最终效果是一样的。
称天平
根据上述优化三进制编码我们就知道每次称天平时左右两边应该放什么球了:
左边 |
右边 |
|
第一次 |
5、10、11、12 |
6、7、8、9 |
第二次 |
2、3、4、10 |
8、9、11、12 |
第三次 |
1、3、7、12 |
4、6、9、10 |
填写好这个表格后再编写程序就很简单了:
# 代码:解决12小球问题# 给出每个小球的轻重编码:
CODES=[
['001', '002'],
['010', '020'],
['011', '022'],
['012', '021'],
['100', '200'],
['202', '101'],
['201', '102'],
['220', '110'],
['222', '111'],
['112', '221'],
['120', '210'],
['121', '212']]def get_balls(i):# 根据第i列每个小球的重码把小球左右分开left = []right = []for index, (code, _) in enumerate(CODES):if code[i] == '1':left.append(index+1) # 小球的编号从1开始elif code[i] == '2':right.append(index+1)return left, rightdef find_ball(code):for i, (heavy, light) in enumerate(CODES):if(heavy == code):return i+1, 'heavy'elif(light == code):return i+1, 'light'return None, Noneif __name__ == '__main__':print('请指定1~12中一个小球是坏球,并且指定它比好球重一点还是轻一点')answers = []for i in range(3):left, right = get_balls(i) # 从编码获取天平两边的小球print('第%d次称天平,请告知天平的状态' % (i+1))print('天平左边的小球:', left, '\t右边的小球:', right)answer = input('请输入(0-平衡, 1-左边低, 2-右边低)')answers.append(answer)answers = ''.join(answers)ball, heavy = find_ball(answers)if ball is None:print('错误的输入')else:print('%d号球是坏球,并且是%s球' % (ball, '重' if heavy else '轻'))
写好这个程序后,我请我太太默选一个小球当作坏球,不要告诉我它是轻的还是重的,只需告诉我天平每次的状态。她说:第一次左边低,第二次平,第三次左边低。于是我就得到编码“101”,然后查上表得知这个坏球是6号球,并且是个轻球。于是我太太夸我真聪明并给了我一个香吻。
Python解决12小球问题相关推荐
- python小球方案问题_Python解决抛小球问题 求小球下落经历的距离之和示例
本文实例讲述了Python解决抛小球问题 求小球下落经历的距离之和.分享给大家供大家参考,具体如下: 问题: 小东和三个朋友一起在楼上抛小球,他们站在楼房的不同层,假设小东站的楼层距离地面N米,球从他 ...
- python中小球落地问题_Python解决抛小球问题 求小球下落经历的距离之和示例
本文实例讲述了Python解决抛小球问题 求小球下落经历的距离之和.分享给大家供大家参考,具体如下: 问题: 小东和三个朋友一起在楼上抛小球,他们站在楼房的不同层,假设小东站的楼层距离地面N米,球从他 ...
- python解决直线过网格问题_numpy_matplotlib
python解决直线过网格问题_numpy_matplotlib 文章目录 python解决直线过网格问题_numpy_matplotlib 1. 问题引子 2. 改良和更新 3. 验证与实例 1. ...
- 用python解决五格与起名问题
用python解决五格与起名问题 大二的暑假闲来无事,恰逢python自学刚刚入门,为了巩固知识,于是想通过python来解决日常生活中的一些问题. 关于姓名的学问--五格 如何取一个好听又好看的名字 ...
- 超难的智力题:12小球问题
设有12个外表一模一样的小球,其中11个重量完全相同,被称为好球,1个重量比好球重一点或者轻一点,被称为坏球.现在给你一架天平,请用天平称3次,把这个坏球找出来,还要知道它到底是轻的还是重的. 注意, ...
- Python解决矩阵的PLU分解及求矩阵的逆
Python解决矩阵的PLU分解及求矩阵的逆 关于PLU的分解基础知识就不叙述了,可以自己去看矩阵分析的书,大体上和高斯消去法差不多. PLU分解被经常用在Ax=bAx=bAx=b的求解上 在这里xx ...
- 唱吧php文件,python解决唱吧歌词解密的问题?
做唱吧歌词解密的时候选择了语言python,对于字节解码的时候用到了chr函数,但是chr函数参数限制在0 ~ 0xff(255),如果需要chr的值出现负数怎么办呢?我记得php用chr函数的时候支 ...
- 高德API+Python解决租房问题
项目简介:编写Python脚本爬取某租房网站的房源信息,利用高德的 js API 在地图上标出房源地点,划出距离工作地点1小时内可到达的范围,附上公交路径规划功能查看不同路径的用时. 本教程由ekCi ...
- Python版本的数据结构书_《用Python解决数据结构与算法问题》
源于经典 数据结构作为计算机从业人员的必备基础,Java, c 之类的语言有很多这方面的书籍,Python 相对较少, 其中比较著名的一本 problem-solving-with-algorithm ...
- Python解决The truth value of a Series is ambiguous.md
Python解决The truth value of a Series is ambiguous.md import pandas as pd data = pd.read_csv('x.csv') ...
最新文章
- JDK 11版本时间表
- MATLAB从入门到精通:MATLAB 图形操作
- C++字符串和数字转换完全攻略
- JavaWeb:脚本标识
- linux 编译安装picocom,Linux pico命令
- WEBGL学习【四】模型视图矩阵
- python 执行js打开链接_使用Python在链接的href中执行JavaScript
- android 在指定位置添加布局,Android 如何动态添加 View 并显示在指定位置。
- 数据挖掘在电信欺诈侦测中的应用
- 学习《TCP/IP详解 卷一协议》第九章的一点心得
- maze3D-一款三维迷宫游戏
- android 新浪微博分享提示签名错误,Android ShareSDK 微博分享 (8995)app auth fail for appKeysignpackage 解决...
- 【Windows】WPS | 多级编号 | 自定义多级标号
- 【机器学习笔记2】多元线性回归模型
- 开发愤怒的小鸟的Lua语言:Wax框架详解
- 语音论文优选:口语理解A Streaming End-to-End Framework For SLU
- 腾讯王卡运营坑之一:web容器优雅停机缓慢
- 【软考软件评测师】第三十三章 数据库系统应用
- H 小P的数学问题(分块)
- 【目标检测算法】YOLO-V5实战检测VOC2007数据集