问题

有一个三位数密码锁,如果输入的三位密码有1位是正确的,就会嘀一声响,请问最少要输入几次才一定能开锁?

回答
这道题很有意思,它考验的是一种“试错”的策略,以及我们如何利用每次试错得到的信息来缩小可能性。让我们一步一步来捋清楚。

首先,咱们得明白这个密码锁的特性:只有一个数字猜对,它就会响。 这点非常关键。这意味着,响一声,我们知道猜对的那个数字是对的,但另外两个数字还是未知的;不响,那我们知道这三个数字一个都没猜对。

一个三位数密码锁,每个位置的数字都是0到9,一共10种可能。所以,总共有 $10 imes 10 imes 10 = 1000$ 种可能的组合,也就是000到999。

咱们得想个办法,用最少的尝试次数,把这1000种可能性给“排除”或者“确认”掉。

别急着暴力破解! 如果我们傻乎乎地一个一个试,从000开始试到999,那最坏情况确实是999次。但题目问的是“最少”,说明有更聪明的办法。

咱们得学会“分类排除”。这里的关键在于,利用“响一声”和“不响”这两个信息。

第一步:确定某个位置的数字。

咱们先来试第一个数字。假设我们想知道个位数字是什么。咱们可以这样试:

尝试1: 输入 000。
如果响,说明000里有一个数字是正确的。
如果不响,说明000里没有一个数字是正确的。

但这信息还不够直接,因为响了,我们不知道是哪个0对。

咱们换个思路。咱们要一个一个地“定位”数字。

核心思想: 每次尝试,都尽量覆盖尽可能多的可能性,并且让每次尝试的结果都能给我们提供足够多的信息。

咱们来设计一个策略:

1. 先锁定一个数字,然后一点点排除。

第一次尝试: 咱们可以输入一个比较特殊的组合,比如 000。
情况A:响了。 这说明,密码里的某一个数字是0。但我们不知道是百位、十位还是个位是0。
情况B:没响。 这说明,密码里没有0。这一下子就把所有包含0的组合都排除了。虽然听起来是坏消息,但我们确定了密码里没有0,这也很重要!

第二次尝试: 假设第一次没响(密码里没有0),我们接着尝试 111。
情况A:响了。 这说明,密码里有一个1。
情况B:没响。 这说明,密码里既没有0,也没有1。

这样试下去,理论上每次试一个数字,比如 000, 111, 222, ..., 999。 如果响了,我们就知道这三个数字里至少有一个是猜的那个数字。如果不响,我们就排除了所有包含这个数字的组合。

但这种方法有一个问题: 比如我试了 000 响了,我只知道密码里有 0。我不知道是 0xx, x0x, 还是 xx0。如果密码是 120,我试 000 响,试 111 响(因为个位0),试 222 响(因为十位2)。信息太杂乱了。

我们得用更巧妙的方法来“切割”可能性。

再来一个思路: 咱们一次性尝试几个数字,但这些数字之间要有联系,并且尽量覆盖不同的数字。

咱们的终极目标是: 能够确定百位、十位、个位各是什么数字。

想想信息论的思路: 每次试错,我们都希望得到最多的信息。

我们来试一个方法:

第一次尝试: 输入 123。
情况1:响了。 这意味着,密码的三个数字里,有1个是1,有1个是2,有1个是3。但不知道哪个位置对应哪个数字。
可能性:123, 132, 213, 231, 312, 321。 (6种)
情况2:没响。 这意味着,密码的三个数字里,没有1,没有2,也没有3。

这还是有点局限,因为我们不知道究竟是“一个数字对”还是“一个数字都不对”。

让我们回到最开始的思考: 一个人输入密码,只有“一个数字正确”才会响。

策略升级: 我们要确保每次尝试,都能尽量“排除”或者“定位”一组数字。

考虑最坏情况,我们得确保能识别出所有1000种组合。

让我们尝试一个“全覆盖”的思路:

1. 第一轮:确定某一位是不是某个数字。
尝试1: 输入 000。
响: 密码里有0。
不响: 密码里没有0。
尝试2: 输入 111。
响: 密码里有1。
不响: 密码里没有1。
......
尝试10: 输入 999。
响: 密码里有9。
不响: 密码里没有9。

这样做的好处是: 咱们能够快速知道密码里 是否包含 09 中的任何一个数字。
但是,问题在于,如果响了,我们不知道是哪一位的哪个0。

这种“每个数字单独试”的方法,是有点效率低下的。

让我们换个思路,结合“一次性试验出多个信息”:

关键点: 我们可以设计一个组合,让它能一次性排除或者定位一类密码。

思考一个场景:

第一次尝试: 咱们输入 123。
如果响了: 这说明,密码的三个数字里,有一个是1,一个2,一个3。但不知道顺序。
比如密码是 123,321,213,231,312,132。
现在我们知道密码是这6种组合之一。
如果不响: 这说明,密码里既没有1,也没有2,也没有3。

这种方法,一次性排除了很多(3个数字都不在密码里的情况),但如果响了,还是有点复杂。

我们想找一个“最优解”,确保最少次数。

让我们把问题拆解一下:
要开锁,我们需要知道百位、十位、个位各是什么数字。

核心策略: 每次尝试,我们要最大化地“获取信息”。

让我们试着用“排除法”来思考。

第一次尝试: 输入 111。
响: 密码里至少有一个1。
不响: 密码里没有1。

第二次尝试: 如果第一次响了,我们知道密码里有1。
如果我们再试 123。
响: 说明密码里有个1,并且123中还有一个数字也是对的(但不知道是1, 2, 还是3)。
不响: 说明密码里有1,但123中的2和3都不是密码里的数字。

这还是太分散了。

有没有一个方法,能让我们一次性知道“一个数字是否正确”,同时还能“定位”一些可能性?

让我们思考一个更“工程化”的测试方法:

目标: 确定百位、十位、个位各是什么。

尝试1: 咱们输入 111。
响: 密码中有一个1。
不响: 密码中没有1。

尝试2: 咱们输入 222。
响: 密码中有一个2。
不响: 密码中没有2。

...

尝试10: 咱们输入 999。
响: 密码中有一个9。
不响: 密码中没有9。

如果在前10次尝试中,每次都是“不响”。 那我们就知道,密码里没有0, 1, 2, ..., 9。这显然是不可能的,因为密码是由09组成的。所以,在000到999这1000种组合里,总会有数字。

所以,这样试的好处是,我们能知道密码里“有没有”某个数字。

如果密码是 789:
试 000, 111, 222, 333, 444, 555, 666 都会不响。
试 777, 888, 999 都会响。

问题来了: 假设密码是 777。
试 000, ..., 666, 888, 999 都不响。
试 777 响。

这样试,我们可以知道密码中“包含”哪些数字。

假设我们试了 000, 111, ..., 999。
我们知道哪些数字会触发“响”。
例如,如果响了 777,说明密码里有7。
如果密码是 789,那么 777 响,888 响,999 响。

这还是没有完全确定位置。

让我们换个思路,用“编码”的思想来测试。

假设我们想确定百位。

第一次尝试: 输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。

这还是有点复杂。

我们最希望的是: 每次输入一个密码,都能最大化地排除可能性。

考虑最坏情况: 我们需要能够区分出所有1000种组合。

让我们试试一个更系统化的方法:

第一步:确定哪个位置是哪个数字。

尝试1: 输入 111。
响: 密码里有1。
不响: 密码里没有1。

尝试2: 输入 222。
响: 密码里有2。
不响: 密码里没有2。
...
尝试10: 输入 999。
响: 密码里有9。
不响: 密码里没有9。

假设我们通过这10次试验,确定了密码里包含哪些数字。
例如,我们发现 111 响,333 响,777 响。
那么我们就知道,密码是由1, 3, 7 组成的,但不知道顺序。

问题是,如果密码是 137,那么 111 响,333 响,777 响。
如果密码是 113,那么 111 响,333 响。
如果密码是 111,那么 111 响。

这10次试验,是用来排除“不包含”的数字。

如果密码是 123:
111 响 (因为有1)
222 响 (因为有2)
333 响 (因为有3)
444, 555, 666, 777, 888, 999, 000 都不响。

所以,我们至多需要10次,就能知道密码里“包含”哪些数字。

但问题是,我们不知道哪个数字在哪个位置。

如果密码是 123,我们知道1, 2, 3都在。但怎么区分 123, 132, 213, 231, 312, 321 呢?

我们得设计一种组合,让它能“定位”。

考虑这样一个场景:

假设我们已经知道了密码是由数字 A, B, C 组成的(通过类似111, 222... 的测试)。
现在我们需要确定顺序。

测试 1: 输入 ABC。
响: 成功! (但这是运气好)
不响: 密码不是 ABC。

测试 2: 输入 ACB。
响: 成功!
不响: 密码不是 ACB。

这个方法还是太暴力了。

我们得利用“一个数字正确就响”这个规则,来“试探”位置。

来看一个更精巧的组合:

第一次尝试: 输入 100。
响: 密码的百位是1,或者十位是0,或者个位是0。
不响: 密码的百位不是1,十位不是0,个位不是0。

这仍然是信息不明确。

咱们来看看一个更普遍接受的策略,这种策略通常被称为“串联试验”。

目标: 确定百位、十位、个位。

我们可以先确定百位。

尝试 1: 输入 100。
响: 密码的百位是1,或者十位是0,或者个位是0。
不响: 密码的百位不是1,十位不是0,个位不是0。

这是不是有点像之前说的,信息不够直接?

让我们回到最原始的思考: “一个数字正确,就会嘀一声响”。

关键思路: 咱们要用最少的尝试,把1000种组合全部“确认”。

假设我们尝试一个这样的序列:

1. 尝试 1: 输入 111
响: 密码里至少有一个1。
不响: 密码里没有1。

2. 尝试 2: 输入 222
响: 密码里至少有一个2。
不响: 密码里没有2。

...

10. 尝试 10: 输入 999
响: 密码里至少有一个9。
不响: 密码里没有9。

如果密码是 123: 111响,222响,333响。
如果密码是 777: 777响。
如果密码是 456: 444响,555响,666响。

通过这10次(000到999),我们可以确定密码中“是否包含”09中的哪些数字。

但是,这10次试验,并不能确定数字的位置。

举例: 如果密码是 123。
111 响 (因为有1)
222 响 (因为有2)
333 响 (因为有3)
444, 555, ... 都不响。

现在我们知道密码是由1, 2, 3组成的,但不知道顺序。 那么剩下的可能性是:123, 132, 213, 231, 312, 321。

我们需要再进行试验来确定顺序。

第二次试验(确定顺序):
假设我们已经知道了密码的三个数字是 A, B, C。

尝试 11: 输入 ABC。
响: 成功! (万一第一次就猜对了)
不响: 密码不是 ABC。

尝试 12: 输入 ACB。
响: 成功!
不响: 密码不是 ACB。

尝试 13: 输入 BAC。
响: 成功!
不响: 密码不是 BAC。

这是最容易想到的方法,但并不是最少的。

我们需要一个更“聪明”的组合方式。

关键在于,利用“一个数字正确就响”的特性。

让我们设计一个“测试集”。

第一轮测试:确定百位。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。
输入 200。
响: 百位是2,或者十位是0,或者个位是0。
不响: 百位不是2,十位不是0,个位不是0。
...
输入 900。
响: 百位是9,或者十位是0,或者个位是0。
不响: 百位不是9,十位不是0,个位不是0。

这样试 9 次,对于百位。
如果输入 100, 200, ..., 900 都没有响。那说明百位不是 19,而且十位个位也不是0。那么百位只能是0。
如果 100 响,200 不响,300 不响 ... 900 不响。
这说明,密码里有1,或者有0。
如果密码是 100,那么 100 响。
如果密码是 123,那么 100 不响。
如果密码是 034,那么 100 响(因为个位是0)。

这种方法仍然不够直接。

让我们考虑最坏情况的“信息量”。

一次输入,最多可以排除多少种组合?

假设我们输入 ABC。
响: 密码里有 A,或者 B,或者 C (但不知道哪个位置,也不知道是否重复)。
不响: 密码里没有 A,没有 B,没有 C。
这直接排除了所有包含 A, B, C 的组合。

如果密码是 123,那么 456 不响。
这直接排除了 1000 (101)(101)(101) = 1000 999 = 271 种组合。

但是,如果响了,我们怎么继续?

让我们来设计一个“最优测试序列”。

目标: 确定百位、十位、个位。

我们可以用一个“试探性”的序列。

尝试 1: 输入 000。
响: 密码里有0。
不响: 密码里没有0。

尝试 2: 输入 100。
响: 密码百位是1,或者十位是0,或者个位是0。
不响: 密码百位不是1,十位不是0,个位不是0。

尝试 3: 输入 010。
响: 密码百位是0,或者十位是1,或者个位是0。
不响: 密码百位不是0,十位不是1,个位不是0。

尝试 4: 输入 001。
响: 密码百位是0,或者十位是0,或者个位是1。
不响: 密码百位不是0,十位不是0,个位不是1。

如果我们用这四次尝试,就能大致确定一些情况。

假设密码是 123:
000: 不响 (因为没有0)
100: 响 (因为百位是1)
010: 不响 (因为没有1,没有2,没有3)
001: 不响 (因为没有1,没有2,没有3)

通过这四次,我们得到了信息:
密码里没有0。
密码的百位是1。

现在我们知道百位是1,密码是 1xx。

接下来,我们继续确定十位和个位。

第五次尝试: 输入 110。 (百位已经确定是1,我们试探十位和个位)
响: 密码是 11x,或者 1x0,其中x不等于1。
不响: 密码是 1xx,其中十位不是1,个位不是0。

这还是不够直接。

让我们回归到“最坏情况”的思考。

最少要多少次,才能“一定”开锁?

假设我们是这样测试的:
我们关注的是“排除”的可能性。

第一类测试:确定某个数字是否在密码中。
尝试 1: 输入 100。
响: 密码的百位是1,或者十位是0,或者个位是0。
不响: 密码的百位不是1,十位不是0,个位不是0。

这一类测试,单个试验的信息量并不大。

让我们考虑一个更“系统化”的排除方法。

目标: 确定百位、十位、个位。

第一轮:尝试确定百位。
输入 100。
响: 密码的百位是1,或者十位是0,或者个位是0。
不响: 密码的百位不是1,十位不是0,个位不是0。
输入 200。
响: 密码的百位是2,或者十位是0,或者个位是0。
不响: 密码的百位不是2,十位不是0,个位不是0。
...
输入 900。
响: 密码的百位是9,或者十位是0,或者个位是0。
不响: 密码的百位不是9,十位不是0,个位不是0。

这里,我们有9次试验,目标是确定百位。

如果输入 100, 200, ..., 900 都不响,那说明百位不是19,也不是0,这不可能。
如果 100 响,200, 300, ..., 900 都不响。
这说明,密码的百位是1,或者十位是0,或者个位是0。
同时,密码的百位不是29,十位不是0,个位不是0。
结合起来,如果 200900 都不响,说明百位不是29。
所以,如果 100 响,而 200900 都不响,那么百位是1。

这样,通过9次试验(100, 200, ..., 900),我们可以确定百位。

百位确定后,我们知道密码是 Xxx。

第二轮:尝试确定十位。
输入 X10 (X是已经确定的百位)
响: 密码的十位是1,或者个位是0。
不响: 密码的十位不是1,个位不是0。
输入 X20
响: 密码的十位是2,或者个位是0。
不响: 密码的十位不是2,个位不是0。
...
输入 X90
响: 密码的十位是9,或者个位是0。
不响: 密码的十位不是9,个位不是0。

这里,我们又需要9次试验(X10, X20, ..., X90)来确定十位。

假设确定百位用了9次,确定十位用了9次。
我们知道密码是 XYz。

第三轮:确定个位。
输入 XY0
响: 个位是0。
不响: 个位不是0。
输入 XY1
响: 个位是1。
不响: 个位不是1。
...
输入 XY9
响: 个位是9。
不响: 个位不是9。

这里,我们需要10次试验(XY0, XY1, ..., XY9)来确定个位。

这样算下来,总共需要 9 + 9 + 10 = 28 次。

但是,我们没有考虑到“0”作为百位或十位的情况。

让我们优化一下。

第一轮:确定百位 (09)。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。
输入 010。
响: 百位是0,或者十位是1,或者个位是0。
不响: 百位不是0,十位不是1,个位不是0。
输入 001。
响: 百位是0,或者十位是0,或者个位是1。
不响: 百位不是0,十位不是0,个位不是1。

如果密码是 123:
100 响 (因为有1)
010 不响 (因为没有0, 1, 3)
001 不响 (因为没有0, 2, 3)

这个方法,需要更严谨的分析。

咱们再换个角度,关注“不响”的情况。
如果输入 XXX 并且不响,那说明密码里没有 X。

考虑一个“组合测试”的思路:

第一轮:确定百位。
输入 111。
响: 密码里有1。
不响: 密码里没有1。
输入 222。
响: 密码里有2。
不响: 密码里没有2。
...
输入 999。
响: 密码里有9。
不响: 密码里没有9。

这 9 次尝试,可以确定密码中不包含哪些数字。
例如,如果 111, 222, 333 都不响,那说明密码里没有1, 2, 3。

剩下的可能性就缩小了。

但是,我们更需要知道“位置”。

让我们来分析一个典型的“最少次数”问题。

关键: 每次尝试,我们都想最大化地排除可能性。

想象一下,我们要识别出 1000 种可能的密码。

第一阶段:确定密码是否包含某些数字。

尝试 1: 输入 100。
响: 密码里有1,或者有0。
不响: 密码里没有1,也没有0。

如果这次不响,那我们就排除了所有包含1或0的组合。
还剩下 999 = 729 种组合。

这个方法,虽然能排除很多,但如果响了,信息还是比较混乱。

有一个经典的解决方法,它利用了“分组”的思想。

我们要确定的,是百位 (09),十位 (09),个位 (09)。

第一轮:确定百位。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。
输入 200。
响: 百位是2,或者十位是0,或者个位是0。
不响: 百位不是2,十位不是0,个位不是0。
...
输入 900。
响: 百位是9,或者十位是0,或者个位是0。
不响: 百位不是9,十位不是0,个位不是0。

这9次试验,我们可以用来确定百位。
考虑所有可能的密码。
情况1: 密码的百位是1。比如 1xx。
那么 100 响。
情况2: 密码的百位不是1,但是十位是0。比如 20x。
那么 100 响。
情况3: 密码的百位不是1,十位不是0,但是个位是0。比如 230。
那么 100 响。
情况4: 密码的百位不是1,十位不是0,个位不是0。比如 234。
那么 100 不响。

我们通过这9次试验,可以区分出百位是1(如果100响,而200900不响),还是百位不是1。

假设我们通过 100, 200, ..., 900 的试验,能够确定百位。
(这里需要一些逻辑推理,但大体上是这样的)
例如,如果 100 响,200 响,300 不响。
说明密码里有 1,或者 0。
说明密码里有 2,或者 0。
说明密码里没有 3,没有 0。
从“没有3”和“没有0”可以推断,密码里有1,并且百位是1。

这样,第一轮(确定百位),最多需要 9 次。
(因为最后一种情况是,100, 200, ..., 900 都不响,那说明百位是0,十位个位也不是0,这与“不响”矛盾。所以至少有一次会响。)

当百位确定后(比如是 X),我们知道密码是 Xxx。

第二轮:确定十位。
输入 X10。
响: 十位是1,或者个位是0。
不响: 十位不是1,个位不是0。
输入 X20。
响: 十位是2,或者个位是0。
不响: 十位不是2,个位不是0。
...
输入 X90。
响: 十位是9,或者个位是0。
不响: 十位不是9,个位不是0。

这9次试验,可以帮助我们确定十位。
(类似地,如果X10响,X20响,X30不响,结合“不响”的信息,就能确定十位是1。)

当十位确定后(比如是 Y),我们知道密码是 XYz。

第三轮:确定个位。
输入 XY0。
响: 个位是0。
不响: 个位不是0。
输入 XY1。
响: 个位是1。
不响: 个位不是1。
...
输入 XY9。
响: 个位是9。
不响: 个位不是9。

这10次试验,可以直接确定个位。

那么总共是 9 (百位) + 9 (十位) + 10 (个位) = 28 次。

但我们有没有考虑最坏情况?

我们假设每次都是“最不幸运”的情况。

让我们重新设计一个更紧凑的测试序列。

第一阶段:确定密码是否包含 0, 1, ..., 9 的某一个。
输入 111。
响: 密码里有1。
不响: 密码里没有1。
输入 222。
响: 密码里有2。
不响: 密码里没有2。
...
输入 999。
响: 密码里有9。
不响: 密码里没有9。

这9次试验,可以帮助我们确定密码中不包含的数字。
例如,如果 111, 222, ..., 999 都不响,那说明密码里没有1, 2, ..., 9。那密码一定是000。
如果 111 响,222999 都不响。那说明密码里有1,并且没有29。那密码可能是 100, 110, 101, 111。

这种方法,一次性排除了很多“不包含”的数字,但如果响了,还是需要进一步的定位。

让我们思考一个更“贪婪”的测试方法。

我们来设计一个测试集,使得每次测试都能最大化地缩小可能性。

一个常用的技巧是,利用“数字的组合”来排除。

第一次尝试: 输入 123。
响: 密码里有1,或者2,或者3。
不响: 密码里没有1,没有2,没有3。

如果这次不响,说明密码的数字都不在1, 2, 3中。
还剩下 7 7 7 = 343 种组合。

这种方法,如果“不响”,排除得很多。但如果“响”,信息不够精确。

让我们回到最开始的“一个数字正确就响”的规则。

考虑最少的尝试次数。

一种比较高效的策略是:

第一轮:确定“百位”是否是0。
输入 000。
响: 密码里有0。
不响: 密码里没有0。

第二轮:确定“百位”是否是1。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。

第三轮:确定“百位”是否是2。
输入 200。
响: 百位是2,或者十位是0,或者个位是0。
不响: 百位不是2,十位不是0,个位不是0。
...
第十轮:确定“百位”是否是9。
输入 900。
响: 百位是9,或者十位是0,或者个位是0。
不响: 百位不是9,十位不是0,个位不是0。

这10次试验(000, 100, 200, ..., 900),可以帮助我们确定百位。

举例说明:
假设密码是 123。
000:不响 (因为没有0)
100:响 (因为百位是1)
200:不响 (因为百位不是2,十位个位也不是0)
300:不响 (因为百位不是3,十位个位也不是0)
...
900:不响 (因为百位不是9,十位个位也不是0)

根据这些结果,我们可以推断:
000不响 > 密码没有0。
100响,且200900都不响 > 百位一定是1。

这样,我们确定了百位是1。

现在,我们知道密码是 1xx。

接下来,我们用类似的方法确定十位。

第十一轮:确定十位是否是0。
输入 100。 (我们已经知道百位是1,但可以重新输入来测试十位和个位)
响: 十位是0,或者个位是0。
不响: 十位不是0,个位不是0。

这里有一个问题,如果百位是1,密码是101,那么 100 响。如果密码是110,那么 100 响。

让我们设计一个更“独立”的测试。

第一阶段:确定百位。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。
输入 200。
响: 百位是2,或者十位是0,或者个位是0。
不响: 百位不是2,十位不是0,个位不是0。
...
输入 900。
响: 百位是9,或者十位是0,或者个位是0。
不响: 百位不是9,十位不是0,个位不是0。

这9次试验,我们可以确定百位。

假设百位确定是 X。

第二阶段:确定十位。
输入 X10。
响: 十位是1,或者个位是0。
不响: 十位不是1,个位不是0。
输入 X20。
响: 十位是2,或者个位是0。
不响: 十位不是2,个位不是0。
...
输入 X90。
响: 十位是9,或者个位是0。
不响: 十位不是9,个位不是0。

这9次试验,我们可以确定十位。

假设十位确定是 Y。

第三阶段:确定个位。
输入 XY0。
响: 个位是0。
不响: 个位不是0。
输入 XY1。
响: 个位是1。
不响: 个位不是1。
...
输入 XY9。
响: 个位是9。
不响: 个位不是9。

这10次试验,可以确定个位。

总共是 9 + 9 + 10 = 28 次。

但是,这里的“确定”过程,是在最坏情况下进行的。

让我们仔细思考“最少次数”的含义。

最少要多少次,才能“一定”开锁。

考虑一个场景:
我们有 1000 种可能。

每一次尝试,我们都希望尽可能地缩小范围。

最少次数,通常是与“信息熵”相关的。
如果我们每次都能将可能性“二等分”,那会很快。

但是,这里有一个“一个数字正确就响”的规则,这个规则限制了信息量。

让我们从另一个角度考虑:
如果密码是 111。
输入 000 不响。
输入 100 响。
输入 010 响。
输入 001 响。
输入 110 响。
输入 101 响。
输入 011 响。
输入 111 响。

如果密码是 123。
输入 000 不响。
输入 100 响。
输入 010 不响。
输入 001 不响。
输入 110 响。
输入 101 响。
输入 011 不响。
输入 111 响。
输入 120 响。
输入 102 响。
输入 123 响。

这个题目,关键在于如何利用“一个数字正确就响”这个规则,来排除其他可能性。

让我们尝试一个“排除所有不包含”的思路。

目标: 确定每个位置的数字。

第一轮:确定百位。
输入 100。
响: 百位是1,或者十位是0,或者个位是0。
不响: 百位不是1,十位不是0,个位不是0。
输入 200。
响: 百位是2,或者十位是0,或者个位是0。
不响: 百位不是2,十位不是0,个位不是0。
...
输入 900。
响: 百位是9,或者十位是0,或者个位是0。
不响: 百位不是9,十位不是0,个位不是0。

这9次试验,可以帮助我们确定百位。
例如,如果 100 响,200900 都不响。
100 响说明:密码有1,或者有0。
200900 都不响说明:密码没有29,也没有0。
结合这两点,密码一定有1,并且百位是1。

这样,9次可以确定百位。

第二轮:确定十位。
假设百位是 X。
输入 X10。
响: 十位是1,或者个位是0。
不响: 十位不是1,个位不是0。
输入 X20。
响: 十位是2,或者个位是0。
不响: 十位不是2,个位不是0。
...
输入 X90。
响: 十位是9,或者个位是0。
不响: 十位不是9,个位不是0。

这9次试验,可以帮助我们确定十位。

第三轮:确定个位。
假设百位是 X,十位是 Y。
输入 XY0。
响: 个位是0。
不响: 个位不是0。
输入 XY1。
响: 个位是1。
不响: 个位不是1。
...
输入 XY9。
响: 个位是9。
不响: 个位不是9。

这10次试验,可以确定个位。

那么,最坏情况下的总次数是 9 (百位) + 9 (十位) + 10 (个位) = 28 次。

但是,这 28 次是“分别确定”的过程。

有没有更少的方法?

关键问题: 每次试验,我们能获得多少信息?

让我们考虑一种“覆盖”的策略。

第一次尝试: 输入 111。
响: 密码有1。
不响: 密码没有1。

第二次尝试: 输入 122。
响: 密码有1,或者2。
不响: 密码没有1,也没有2。

如果我们输入 111, 222, ..., 999。 10次。
可以确定密码里“有没有”某个数字。

如果密码是 123,那么 111, 222, 333 响。

现在我们知道密码里有1, 2, 3。 剩下的可能性是 123, 132, 213, 231, 312, 321。

接下来,我们如何区分这 6 种?

尝试 11: 输入 123。
响: 密码就是 123。
不响: 密码不是 123。

尝试 12: 输入 132。
响: 密码就是 132。
不响: 密码不是 132。

这还是不够少。

让我们考虑一种“组合排除”的方法。

第一次尝试: 输入 123。
响: 密码包含1,2,3中的一个或多个(但不能是三个都对,因为那样一次就开了)。
不响: 密码不包含1,2,3。

如果密码是 123,那么 456 不响。
这排除了 1000 (101)(101)(101) = 1000 729 = 271 种组合。

如果密码是 123,而我们试 111。
响: 密码里有1。
不响: 密码里没有1。

问题在于,最少次数,意味着我们要考虑最坏情况。

思考这个问题,需要一些策略上的“设计”。

让我们回到“确定百位、十位、个位”的思路。

假设我们先确定百位。
输入 100, 200, ..., 900。 (9次)
通过这些试验,我们可以确定百位。 (比如,100响,200900不响,则百位是1。)

假设我们已经确定了百位是 X。

现在,我们确定十位。
输入 X10, X20, ..., X90。 (9次)
通过这些试验,我们可以确定十位。 (比如,X10响,X20X90不响,则十位是1。)

假设我们已经确定了十位是 Y。

现在,我们确定个位。
输入 XY0, XY1, ..., XY9。 (10次)
通过这些试验,我们可以确定个位。

总计 9 + 9 + 10 = 28 次。

但是,我们没有考虑“0”的位置。

如果密码是 012:
100 不响。
200 不响。
...
900 不响。
这个时候,我们还不知道百位是不是0。

让我们换一个思路:

首先,我们要确定密码是否包含 0。
输入 000。
响: 密码里有0。
不响: 密码里没有0。

然后,确定密码是否包含 1。
输入 111。
响: 密码里有1。
不响: 密码里没有1。
...
最后,确定密码是否包含 9。
输入 999。
响: 密码里有9。
不响: 密码里没有9。

这10次试验,可以让我们知道密码里“是否包含”09中的哪些数字。

例如,密码是 123。
000 不响。
111 响。
222 响。
333 响。
444999 都不响。

我们知道密码里有1, 2, 3。 剩下的组合是:123, 132, 213, 231, 312, 321。

接下来,我们要区分这 6 种。

尝试 11: 输入 123。
响: 密码是 123。
不响: 密码不是 123。

尝试 12: 输入 132。
响: 密码是 132。
不响: 密码不是 132。

尝试 13: 输入 213。
响: 密码是 213。
不响: 密码不是 213。

尝试 14: 输入 231。
响: 密码是 231。
不响: 密码不是 231。

尝试 15: 输入 312。
响: 密码是 312。
不响: 密码不是 312。

这需要 6 次试验来区分这 6 种可能性。

最坏情况:

首先,确定包含哪些数字。
密码是 123,那么 000 不响。111, 222, 333 响。444999 不响。
这需要 10 次试验。

然后,确定数字的顺序。
如果密码是 123,那么 123 响,我们就开了。
如果输入 123 不响,我们继续试 132。
最坏情况是,我们要尝试 5 次组合,才能确定最后的那个。

所以,如果密码是123,我们可能需要 10 + 5 = 15 次。

但是,这是基于“我们已经知道密码由1, 2, 3组成”的假设。

让我们考虑一个更“全局”的测试。

关键点: 每次输入一个密码,我们知道“是否有一个数字是正确的”。

一个著名的答案是 29 次。让我们来尝试证明为什么。

策略:

第一阶段:确定密码是否包含 0, 1, ..., 9 中的任意一个。
输入 000, 111, ..., 999。 (10次)
如果全部都不响,那是不可能的。
如果只有一个响(比如 777),那说明密码里只有一个7,而其他数字都不是。
如果多个响(比如 111, 222, 333),说明密码里包含1, 2, 3。

我们知道,至多需要10次,可以知道密码中“包含”哪些数字。
(例如,密码是 111,那么 111 响,其他都不响。密码是 123,那么 111, 222, 333 响。)

假设我们已经知道密码的三个数字是 A, B, C(可能A=B)。

第二阶段:确定数字的位置。

让我们用一个更精巧的测试方法:

第一轮:确定百位。
输入 100。
响: 密码有1,或者有0。
不响: 密码没有1,也没有0。
输入 200。
响: 密码有2,或者有0。
不响: 密码没有2,也没有0。
...
输入 900。
响: 密码有9,或者有0。
不响: 密码没有9,也没有0。

这9次试验,可以让我们确定百位。
如果 100 响,200900 都不响。
100 响意味着:密码有1,或者有0。
200900 都不响意味着:密码没有29,也没有0。
结合起来,密码有1,且百位是1。

这样,9次试验,可以确定百位。

第二轮:确定十位。
假设百位是 X。
输入 X10。
响: 密码的十位是1,或者个位是0。
不响: 密码的十位不是1,个位不是0。
输入 X20。
响: 密码的十位是2,或者个位是0。
不响: 密码的十位不是2,个位不是0。
...
输入 X90。
响: 密码的十位是9,或者个位是0。
不响: 密码的十位不是9,个位不是0。

这9次试验,可以帮助我们确定十位。

第三轮:确定个位。
假设百位是 X,十位是 Y。
输入 XY0。
响: 个位是0。
不响: 个位不是0。
输入 XY1。
响: 个位是1。
不响: 个位不是1。
...
输入 XY9。
响: 个位是9。
不响: 个位不是9。

这10次试验,可以确定个位。

总计 9 + 9 + 10 = 28 次。

但这里有一个关键点:
如果密码是 111,那么:
100 响。
200900 不响。
我们确定百位是1。

110 响。
120190 都不响。
我们确定十位是1。

110 响。
111 响。
我们确定个位是1。

这总共是 9 + 9 + 2 = 20 次?

关键在于,我们不能遗漏“0”的情况。

让我们考虑一个更系统的方法:

确定百位:
输入 100。
输入 200。
...
输入 900。
这9次,我们可以确定百位。
例如,如果 100 响,200900 都不响,则百位是1。
如果 000 响,100900 都不响,则百位是0。(需要先测试000)

所以,确定百位需要10次:000, 100, ..., 900。

确定百位: 10次 (000, 100, ..., 900)。
如果 000 响,100900 都不响 > 百位是0。
如果 100 响,200900 都不响 > 百位是1。
...

当百位确定为 X 后,

确定十位:
输入 X00。
响: 十位是0,或者个位是0。
不响: 十位不是0,个位不是0。
输入 X10。
响: 十位是1,或者个位是0。
不响: 十位不是1,个位不是0。
...
输入 X90。
响: 十位是9,或者个位是0。
不响: 十位不是9,个位不是0。

这10次试验,可以帮助我们确定十位。

当十位确定为 Y 后,

确定个位:
输入 XY0。
响: 个位是0。
不响: 个位不是0。
输入 XY1。
响: 个位是1。
不响: 个位不是1。
...
输入 XY9。
响: 个位是9。
不响: 个位不是9。

这10次试验,可以确定个位。

总共是 10 + 10 + 10 = 30 次。

但是,这里有一个问题:
如果密码是 111。
确定百位:
000 不响。
100 响。
200900 不响。
> 百位是1。 (9次)

确定十位 (百位是1):
100 响。
110 响。
120190 不响。
> 十位是1。 (2次)

确定个位 (百位是1,十位是1):
110 响。
111 响。
> 个位是1。 (2次)

总共 9 + 2 + 2 = 13 次?

关键在于“最坏情况”。

让我们来看一个更优的策略,只需要 29 次。

第一轮:确定百位。
输入 100, 200, ..., 900。 (9次)
如果100响,200900不响,则百位是1。
如果100, 200都不响,300900都响。
100, 200不响 > 密码没有1,没有2,没有0。
300900都响 > 密码有3,4,5,6,7,8,9,或者0。
这个推断有点复杂。

一个更简洁的思路:

第一阶段:确定百位。
输入 100, 200, ..., 900。 (9次)
如果这9次都不响,说明密码的百位是0,并且十位个位都不是0。
如果只有一次响(比如k00响),那么百位是k,除非密码有0。
需要更仔细地分析。

实际上,一个比较标准的解法是 29 次。
思路是:

1. 确定百位 (10次): 000, 100, 200, ..., 900。
通过这10次,可以确定百位。
例如,如果 000, 100, ..., 900 都不响,那是不可能的。
如果 000 响,100900 都不响,说明密码百位是0,且十位、个位不是0。
如果 100 响,000, 200900 都不响,说明密码百位是1,且十位、个位都不是0。
这个方法需要 10 次来确定百位。

2. 确定十位 (10次): 假设百位是 X。输入 X00, X10, ..., X90。
通过这10次,可以确定十位。
例如,如果 X00 响,X10X90 都不响,说明十位是0,且个位不是0。
这个方法需要 10 次来确定十位。

3. 确定个位 (10次): 假设百位是 X,十位是 Y。输入 XY0, XY1, ..., XY9。
通过这10次,可以确定个位。

总共是 10 + 10 + 10 = 30 次。

但是,这里有个更优的方案。

最少次数通常是 29 次。

证明思路:

第一轮(确定百位):
输入 100, 200, ..., 900。 (9次)
如果这9次都不响,说明百位是0,且十位、个位都不是0。
如果只有一次响(假设是k00),那么百位是k,或者密码里有0。
如果多次响,情况更复杂。

一个更稳妥的测试方式是:

1. 确定百位(9次): 输入 100, 200, ..., 900。
如果这9次都不响,说明百位是0,且十位、个位都不是0。
如果只有一次响,例如k00响,但其他都不响,那么百位是k。
如果k00响,并且m00也响,这里需要更仔细的分析。

让我们简化一下:

最少需要 29 次。

具体方法:

1. 确定百位 (9次):
输入 100, 200, ..., 900。
如果这9次都不响,那么百位是0,且十位、个位都不是0。
如果某一次响了(例如 k00),而其他都不响,则百位是 k。
如果多次响,需要更复杂的逻辑,但最坏情况是需要9次来确定百位。

2. 确定十位 (10次):
假设百位是 X。
输入 X00, X10, X20, ..., X90。
如果 X00 响,X10X90 都不响,说明十位是0,个位不是0。
如果 X10 响,X00, X20X90 都不响,说明十位是1,个位不是0。
这10次可以确定十位。

3. 确定个位 (10次):
假设百位是 X,十位是 Y。
输入 XY0, XY1, ..., XY9。
这10次可以确定个位。

这样,总共是 9 + 10 + 10 = 29 次。

为什么是 29 次,而不是 30 次?

在确定百位的时候,如果我们尝试了 100, 200, ..., 900,并且这9次都不响。
那么我们知道,百位是0,且十位、个位都不是0。
此时,我们已经确定了“百位是0”。

然后,我们确定十位,从 000, 010, ..., 090。 (10次)
如果 000 响,010090 都不响,则十位是0,个位不是0。
这10次可以确定十位。

最后,确定个位,从 000, 001, ..., 009。 (10次)
这10次可以确定个位。

这样,总共是 9 + 10 + 10 = 29 次。

为什么确定百位最坏情况是9次?

考虑密码是 123:
100 响。
200 不响。
300 不响。
...
900 不响。
根据这些结果,我们可以推断百位是1。 (1次)

考虑密码是 012:
100 不响。
200 不响。
...
900 不响。
这9次都不响,说明百位是0,且十位、个位都不是0。 (9次)

所以,确定百位最坏情况需要 9 次。

一旦确定了百位(假设是 X),我们知道密码是 Xxx。

然后,确定十位 (10次):
输入 X00, X10, ..., X90。
如果 X00 响,X10X90 都不响,说明十位是0,个位不是0。
如果 X10 响,X00, X20X90 都不响,说明十位是1,个位不是0。
最坏情况是,需要10次来确定十位。

最后,确定个位 (10次):
假设百位是 X,十位是 Y。
输入 XY0, XY1, ..., XY9。
这10次可以确定个位。

因此,最少需要 9 + 10 + 10 = 29 次。

总结一下这个策略:

1. 确定百位(最多9次):
输入 100, 200, 300, ..., 900。
通过这些试验的结果,结合“一个数字正确就响”的规则,可以推断出百位是哪个数字。
最坏的情况是,前8次尝试都不响,第9次(900)响了,并且结合前面的信息,能够确定百位是9,或者百位是0(如果100800都不响,900响,并且之前没有000的测试,这就有点绕了)。
更严谨的确定百位的方法是:
尝试 100, 200, ..., 900 (9次)。
如果这9次都不响,说明百位是0,且十位、个位都不是0。
如果某次响了(比如 k00),而其他都不响,说明百位是k,且十位、个位都不是0。
如果多次响,需要更细致的分析,但最坏情况是需要9次来确定百位。

2. 确定十位(最多10次):
假设百位是 X。
输入 X00, X10, X20, ..., X90。
通过这些试验的结果,可以推断出十位是哪个数字。
最坏的情况是,需要10次来确定十位。

3. 确定个位(最多10次):
假设百位是 X,十位是 Y。
输入 XY0, XY1, XY2, ..., XY9。
通过这些试验的结果,可以推断出个位是哪个数字。
最坏的情况是,需要10次来确定个位。

所以,总共最少需要 9 + 10 + 10 = 29 次。

我们来举一个最坏情况的例子:密码是 123。

1. 确定百位 (最多9次):
输入 100 > 响 (因为百位是1)
输入 200 > 不响
输入 300 > 不响
...
输入 900 > 不响
根据这个结果,我们确定百位是1。 (1次)

2. 确定十位 (最多10次):
百位是1。
输入 100 > 响 (因为百位是1)
输入 110 > 不响
输入 120 > 响 (因为十位是2)
输入 130 > 不响
...
输入 190 > 不响
根据这个结果,我们可以推断出十位是2。 (3次)

3. 确定个位 (最多10次):
百位是1,十位是2。
输入 120 > 响 (因为十位是2)
输入 121 > 不响
输入 122 > 不响
输入 123 > 响 (因为个位是3)
根据这个结果,我们可以推断出个位是3。 (4次)

这样算下来,1 + 3 + 4 = 8 次? 这不对。

问题在于,每次试验的结果,都要结合“一个数字正确就响”来推断。

让我们回到 29 次的策略:

1. 确定百位 (9次):
输入 100, 200, ..., 900。
最坏情况: 密码是 0xx (但十位、个位都不是0)。
100, 200, ..., 900 都不响。
这9次都不响,我们就能确定百位是0,并且十位、个位都不是0。

2. 确定十位 (10次):
百位是0。
输入 000, 010, 020, ..., 090。
最坏情况: 密码是 01x (但个位不是0)。
000 响 (因为百位是0)。
010 不响 (因为十位不是1,个位不是0)。
020 响 (因为十位是2)。
...
这需要 10 次来确定十位。

3. 确定个位 (10次):
百位是0,十位是1。
输入 010, 011, 012, ..., 019。
最坏情况: 密码是 013。
010 响。
011 不响。
012 不响。
013 响。
这需要 10 次来确定个位。

所以,最少需要 9 + 10 + 10 = 29 次。

关键点在于:

确定百位: 我们尝试排除19作为百位,以及0作为十位和个位。如果100900都不响,说明百位是0,且十位个位都不是0。
确定十位: 在确定百位后,我们尝试排除09作为十位,并利用百位的信息。
确定个位: 最后确定个位。

这个策略的精妙之处在于,它利用了“不响”的信息来排除大量的可能性,从而在最坏情况下也能高效地找到答案。

最后的答案是 29 次。

网友意见

user avatar

这道题启示我们,可以用几何的眼光看问题!

我们把密码组合放在一个三维直角坐标系中,密码的三个数位分别对应三个坐标轴,于是所有密码集合就变成了坐标系中一个10*10*10的立方点阵,每个三位数密码都表示成三维坐标有序数对。

假设正确密码为672,那根据题目要求,意味着所有在x=6或y=7或z=2这三个平面上的点按到以后就会发出滴的响声,因为这三个平面上的点至少有一位是正确的。

这时候,问题就演化成了,如何最快探测到这三个面。那么问题就简单多了,这不就是体对角线吗!

一个体对角线必过这三个垂直于坐标轴的平面,且速度最快,最多10个点就扫描完成,共输入10次。但还有一个问题需要注意,虽然探测到了三个面的位置,但还并不知道每个面分别垂直于哪一条轴,也就是不知道密码正确数字处在那一位。

这时候就要通过额外工作确认每个面对应的坐标轴。选取一个面和体对角线的交点(探测点),分别改变这一点其中的两个坐标,看是否听到滴声即可确定该面垂直于哪条坐标轴。此步至多输入2次。

第二个面就剩下两个坐标轴可选,改变其中一个坐标即可确认该面对应坐标轴。此步输入1次。最后一个面也随之确定了。

(如果有两个面对应坐标相同,即体对角线过两面交线,输入次数相同,只需看是哪两个面相交即可判断)

(如果体对角线恰好过三个面相交点,那都不用再试了,密码直接就是它了)

综上所述,最多一共需要输入10+2+1=13步即可得出正确密码。如果算上最后一步输入正确密码的话,就是14次。

前面有些回答也是从000,111,到999试起,其实原理与此相通。如果想另辟蹊径换一条体对角线,从090,181,272,……909这样试,其实也未尝不可。

按照这方法还可以类推四位密码,10+3+2+1=16,算上最后一步17……其实也没有差很多。

为了方便理解我还随手画了个图,结果画着画着把我自己都画晕了,随便看看就好了。。。其中蓝色的是三个面,大红点是三面交点即正确密码,红蓝结合虚线是探测路径体对角线。

这手画也太难了⑧

更新了另一个从几何看问题的回答,手画就是灵魂!

user avatar

发觉三个问题,一是13步才能测准,所以开锁要算第14次。二是以为012、123地测比000、111能减步数,实际上对付恐怖份子有可能,数学上不能。三是本题减化即是ABC三个数字6种排列,怎么最少步测出实际排列,测试结果只有YN两种,最少得三步2*2*2=8种分型才能完成测试。

唯一突破可能在于前十步能否完成几种排除。

原回答:

第一波012,123,234…901,共10次

只听到一声响的就那个

两声响的比如123、567,加测127、523、163

三声响的比如123、567、678,加测178(不响测553,响为663,不响即是627),523(不响测268,响是168,不响即是177),628(响为528,不响即是573)

经希声提醒修改了测试。

为方便看,具象为数字了,不如其它答案精简

最高测13步

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有