十二硬币问题
==
解题思想源于“约翰·比斯利”(一个歪果仁)
##1、问题重述
给出12个硬币,其中一个是假硬币,用一个天平来确定三种重量的假币(其中假币可能比其他硬币轻或重)。问:至少称量多少次能够保证判断出:是否假币,而且如果有,确定假币是哪一颗,
##2、问题推导
###3颗硬币的情况
我们分析3颗硬币的情况,是为了得出一种分类方法。
三枚硬币测量如图:
经过这两次称重之后,我们可以判断三个信息:
1、是否有假币; 2、假币是哪一颗; 3、假币是轻还是重;
这是三枚硬币的情况,我们称量两次,即可得出上面三个结论。
###9枚硬币的情况
根据三枚硬币的情况,我们将9枚硬币分为三组,
用类似与3枚硬币的方法,两次测量后,我们必然可以得到一下信息(对比三枚硬币情况)
1、是否有假币; 2、假币在哪一组; 3、假币是轻还是重;
如图:
接下来我们要干的事情,就是去确定:在已经判断出有假币的组中,确定假币是哪一颗。
3枚硬币,已经知道假币是轻还是重,再通过一次称量,我们就可以确定假币是哪一颗。
如图:
总结9枚硬币的方法:
9枚硬币,经过3次测量,我们可以获得以下信息:
1、有没有假币; 2、假币是轻是重; 3、假币是哪一颗;
###12枚硬币的情况
在9枚硬币分成3个组的情况下,我们在每个组里加入一枚新硬币,进行第一次称量,如图:
在此基础上,新加入的硬币不换位置,交换9枚硬币的位置,如图:
我们可以得到以下信息:
1、硬币是在新加入的3颗中,还是在原来的9颗中(原来的9颗交换了位置,新加入的3颗没有换位置)
基于此,我们进行下面的判断:
如果硬币是在新加入的3颗中,按照3颗硬币的方法,再称量一次就可以找到假币。
如果硬币实在原来的9颗中,按照9颗硬币的方法,再称量一次也可以找到假币。
如果三次都是平衡,判断出没有假币。
如图:
基于此,我们可以得出结论:
12枚硬币称3次,必定可以找到假币
运用python代码来实现12枚情况的输出:
结果如下:
j ['z', 'z', 'p'] 假币是重的
a ['z', 'p', 'z'] 假币是重的
b ['z', 'p', 'y'] 假币是重的
c ['z', 'p', 'p'] 假币是重的
d ['y', 'z', 'z'] 假币是重的
e ['y', 'z', 'y'] 假币是重的
f ['y', 'z', 'p'] 假币是重的
k ['y', 'y', 'z'] 假币是重的
g ['p', 'y', 'z'] 假币是重的
h ['p', 'y', 'y'] 假币是重的
i ['p', 'y', 'p'] 假币是重的
l ['p', 'p', 'y'] 假币是重的
k ['z', 'z', 'y'] 假币是轻的
e ['z', 'y', 'z'] 假币是轻的
d ['z', 'y', 'y'] 假币是轻的
f ['z', 'y', 'p'] 假币是轻的
j ['y', 'y', 'p'] 假币是轻的
b ['y', 'p', 'z'] 假币是轻的
a ['y', 'p', 'y'] 假币是轻的
c ['y', 'p', 'p'] 假币是轻的
h ['p', 'z', 'z'] 假币是轻的
g ['p', 'z', 'y'] 假币是轻的
i ['p', 'z', 'p'] 假币是轻的
l ['p', 'p', 'z'] 假币是轻的
完毕!
下面是自家原产的python代码
#假设z为左倾,y为右倾,p为平衡,球编号为a~l,situ为情况
#第一次
t1_left="abcj"
t1_right="defk"
t1_undo="ghil"
#第二次
t2_left="defj"
t2_right="ghik"
t2_undo="abcl"
#第三次
t3_left="adgk"
t3_right="behl"
t3_undo="cfij"
#整合
t1=[t1_left,t1_right,t1_undo]
t2=[t2_left,t2_right,t2_undo]
t3=[t3_left,t3_right,t3_undo]#在矩阵中,0为左,1为右,2为平
nb=["z","y","p"]
for i1 in range(3):
cycle_situ=[]
situ1=t1[i1]
for i2 in range(3):
situ2=t2[i2]
for i3 in range(3):
situ3=t3[i3]
#判断公共值
#开始判断
for zi1 in situ1:
for zi2 in situ2:
if zi1==zi2:
for zi3 in situ3:
#遍历三个situ中的字符,判断公共值
if zi2==zi3:
#为输出总的情况准备
cycle_situ.append(nb[i1])
cycle_situ.append(nb[i2])
cycle_situ.append(nb[i3])#把每一次成功找到结果时,天平情况存入矩阵
#print(situ1,situ2,situ3)#可查看成功后具体分组情况
print(zi3,cycle_situ,"假币是重的")
cycle_situ=[]#清空数据
print("\n")#为了让结果输出的时候好看一点
#如果假币为轻,与假币为重不同之处在于,天平右倾,假币在左,天平左倾假币在右,故修改一些假币为重的程序顺序即可
#就只改下面三行
t1=[t1_right,t1_left,t1_undo]
t2=[t2_right,t2_left,t2_undo]
t3=[t3_right,t3_left,t3_undo]#在矩阵中,0为左,1为右,2为平
#完成取轻的一方的操作
nb=["z","y","p"]
all_situ=[]
for i1 in range(3):
cycle_situ=[]
situ1=t1[i1]
for i2 in range(3):
situ2=t2[i2]
for i3 in range(3):
situ3=t3[i3]
#判断公共值
#开始判断
for zi1 in situ1:
for zi2 in situ2:
if zi1==zi2:
for zi3 in situ3:
#遍历三个situ中的字符,判断公共值
if zi2==zi3:
#为输出总的情况准备
cycle_situ.append(nb[i1])
cycle_situ.append(nb[i2])
cycle_situ.append(nb[i3])#把每一次成功找到结果时,天平情况存入矩阵
#print(situ1,situ2,situ3)#可查看成功后具体分组情况
print(zi3,cycle_situ,"假币是轻的")
cycle_situ=[]
###丰丰丰丰丰丰