猜数字游戏
原创大约 5 分钟
使用超过700px宽度的web浏览器查看以获得最佳阅读体验。
从2-80之间(包括2和80)选两个自然数,将他们的积与和分别告诉甲乙两人,假设甲乙两人足够聪明。下面是两人的对话:
- 乙:甲不论如何也猜不到是哪两个数字。
- 甲:我知道了。
- 乙:我也知道了。
请问是哪两个数字?
逻辑分析
乍一看题面根本没有告诉读者有关这两个数字的任何信息,但是仔细思考就会发现:
从题面来看,甲拿到的是两数之积,乙拿到的是两数之和。由于甲乙两人足够聪明,如果甲拿到的是两素数之积,他一定能够猜到这两个数字。
第一句话展示了乙对甲猜不出这两个数字的绝对自信,这表示乙拿到的和不能被分解为两素数之和,否则甲完全有可能拿到这两个素数的积。
第二句话可以理解为:甲将拿到的数因式分解,并对得到的两个数求和,此时有且仅有一种情况,使得这两个数之和不能被分解为两素数之和,这样便可以唯一确定这两个数。
最后一句话也用同样方式理解:乙将拿到的数进行分解,对每种情况进行第3点中甲的计算,能够满足第3点的分解即为正确的分解情况。
问题详解
以下解答由博主本人构思并撰写,可能不规范,请见谅。
设这两个数分别为 和 ( ),那么甲拿到的是 ,记为 ;乙拿到的是 ,记为 。
首先,对于 的所有分解, 和 不能同时为素数。记 里的素数集合为 ,则
其次,对于满足 式的 ,因为 的限制,又有
满足 式的 是确定值,即最终的答案。
因此解题步骤应为:枚举 对满足 式的 计算 判断是否满足 式。
注
如果你是甲,你只需要挑选出和你拿到的 相等的 进行计算。
如果你是乙,你不需要枚举 。
接下来采用启发式搜索:
- :只有1种分解,排除。
- :只有1种分解,排除。
- :有2种分解,其中是两素数,故排除。
- :有2种分解,其中是两素数,故排除。
- :有3种分解,其中是两素数,故排除。
- :有3种分解,其中是两素数,故排除。
- :有4种分解,其中是两素数,故排除。
- :有4种分解。
- :,,只有 不能被分解为两素数。满足要求。
- :,,只有 不能被分解为两素数。满足要求。
- 此时满足要求的 已经多于一个,故排除。
- :有5种分解,其中是两素数,故排除。
- :有5种分解,其中是两素数,故排除。
- :有6种分解,其中是两素数,故排除。
- :有6种分解,其中是两素数,故排除。
- :有7种分解,其中是两素数,故排除。
- :有7种分解。
- :,, 和 都不能被分解为两素数。排除。
- :,, 和 都不能被分解为两素数。排除。
- :,,只有 不能被分解为两素数。满足要求。
- :,, 和 都不能被分解为两素数。排除。
- :,, 和 都不能被分解为两素数。排除。
- :,, 和 都不能被分解为两素数。排除。
- :,, 和 都不能被分解为两素数。排除。
- 满足要求的结果有且仅有 。
因此结果为 。
程序验证
靠人力去挨个遍历肯定是行不通的,要想囊括 里的所有情况,就不得不进行程序验证。
于是按照上述的解题步骤,就有了以下的代码:
Python demo
# Made by Wanakachi
primelist = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157]
def divide_n(n):
product = []
for i in range(2, n//2+1):
# can be divided by 2 prime numbers
if i in primelist and n-i in primelist:
return [], False
# too big
if n-i > 80:
continue
product.append(i*(n-i))
return product, True
def divide_m(product):
res = []
for m in product:
good = []
# from product to sum
for i in range(2, int(m**0.5)+1):
# too big
if i > 80 or m//i > 80:
continue
if m%i == 0:
sum = i+m//i
_, no_prime = divide_n(sum)
if no_prime:
good.append([i, m//i])
# only one sum cannot be divided by 2 prime numbers (where the product comes from)
if len(good) == 1:
res.append(good[0])
# only one product satisfies the condition -> correct numbers
if len(res) == 1:
return res[0], True
return [], False
def main():
for i in range(4, 161):
if i == 160:
pass
product, no_prime = divide_n(i)
if not no_prime:
continue
res, good = divide_m(product)
if good:
print(res)
if __name__ == '__main__':
main()
运行这份代码,控制台只会输出 这一对数字,看来这应该就是该范围内唯一的一组解了。