“猜你心里想的数” 小魔术揭秘

女儿展示了一个小魔术,如下 6 张写满数字的扑克:
在这里插入图片描述
让我心中默默选 1~60 中随意一个数字 x,然后她只依次拿这 6 张扑克问我 x 在不在里面,完事后她就知道 x 是多少。隐约记得哪里看到过这个魔术。

我拿过扑克仔细观察了一阵,想知道怎么回事。如果干别的职业还真容易陷入找规律的路子,但左上角数字还是没躲过码农之眼。记得去年在上海科技馆就看到过有人在炫耀 1,2,4,8,16,…65536,我颇为不屑,我跟家人说这个我也会,不光会这个,我还知道 16 进制 0xffffffff 是 4294967296,这就是职业直觉。

这个魔术很简单,对方只需要知道哪些扑克上有你默选的数字 x,然后将这几张扑克左上角的数字加在一起就是 x。道理也简单,因为 1,2,4,8,16,32 这 6 个数字的排列组合算术和可以编码从 1 到 63 的任何数字。

首先,C(6,1) + C(6,2) + C(6,3) + C(6,4) + C(6,5) + C(6,6) = 6 + 15 + 20 + 15 + 6 + 1 = 63 说明 6 个数字的排列组合算术和有 63 种,其次,1,2,4,8,16,32 是 2 的连续次幂,写成 2 进制就是 1,10,100,1000,10000,100000,最多只用 1 次某个数,就可以表示 2 进制 1 到 111111 中的任何数字,而 111111 就是 63。

这就是答案了,如果你选的是 35,而 35 = 32 + 2 + 1,则只需要在左上角是 32,2,1 的扑克上写上 35 即可,如果你选的是 20,而 20 = 16 +4,则只有左上角为 16,4 的扑克上写有 20。

我们在日常生活中都知道这个道理,10 进制中,为表示 1000 以内连续的所有数字,100,101,10^2 这 3 个数字就足够,每个数字最多用 10 -1 = 9 次,如果是 3 进制,则 30,31,32,33,3^4 能表示连续数字,每个数字最多出现 3 - 1 = 2 次。但我们发现,能以最简单的方式玩这个游戏的只有 2 进制,因此只有 2 进制只需要用 1 次 2 的次幂数字即可,因此只需要简单加和就行了。

其实我们曾经天天都在玩这个游戏,只不过是反着玩,先给出一个数字,然后拆成一些 “基” 数字的加和,尽量每个基数字只用一次,想到是什么了吗?很简单,付钱和找零,这是一个贪心背包。

付钱和找零都尽量不要同一币值的货币给多张,尽量不数钱而只将一眼看穿的币面值做累加,因此尽量每种币面只用一次。

我的货币面值种类是处在 2 进制和 3 进制之间的,以 RMB 为例,它拥有 1,2(曾经有,为了论述方便就当它还有),5,10,20,50,100 的多种面值,它们的排列组合算术运算可以表示从 1 元到 200 以内的任何元钱,1 元钱就是 1 张 1 元,3 元钱是 1 张 1 元 + 1 张 2 元,有趣的是,4 = 2 + 2 之外,还可以是 4 = 5 - 1,这就增加了交易灵活性和货币数量在双方的平衡。

如果是卖者找零也一样的操作。这种 2~3 进制的货币面值发行单位其实在半强制引导人们做二分贪心背包,操作非常简单,假设目标价格是 x,挑最大面值的钱累加做算术和 s,只要 s < x 就继续,如果 s > x 就变换双方角色,如果对方不肯,就找附近的人以当前最大的面值重复这个过程后做等额交换,俗称 “换零钱”。而对于天天买卖的人,特别是商户而言,这些单位币值的排列组合算术和,算术差简直就像程序员对于 2 的不同次幂之间的算术运算一样烂于心了。

如果用纸币玩本文开头介绍的游戏,在 1 元钱上会写上哪些数字呢?显然除了 1 元币值表示它本身,还有所有它参与的所有,比如 3,6,8,11,…,而 5 元钱上会写上 15,25,35,45,…,对于 5 - 1 = 4 这种情况,可以在 5 元钱上写上 4,然后在 1 元钱上在 4 旁边做个记号表示 -1。

总体而言,就文初图片而言,这个游戏迷惑性还是太差了,首先,对程序员那么敏感的数字不该放在那么显眼的位置,其次,其余的数字太连续了不够散列。解决这些问题的方式五花八门,可以将左上角的数字做多次索引才找到真正的 “基” 数字,再混入一些其它运算。

在隐藏在背后的运算面前,结果跟障眼法没什么区别,而逆向这些运算不光看知识和技术,还要看筹码,以及你有没有这个闲心。

浙江温州皮鞋湿,下雨进水不会胖。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个一个房间内互动游戏中,魔术师要求每位观众心里一个三位abc(分别是百位、十位和个位数字),然后魔术师让观众记住abc、bac、bca、cab和cba五个数字以及它们的和值。只要观众能够到这个原abc是多少,就能够真正出现观众心里的原abc,而且同样可以根据观众反映的和值推算出原,如题目所示。请编程模拟这个数字魔术游戏。 ### 回答2: 这个游戏可以用程序来模拟,首先需要确定可行的的范围。由于是三位,所以范围是从100到999。实际上,5个的和值的范围是从911到2289。这意味着我们只需要处理这个范围内的5个的和值,而不必考虑所有可能的三位。 接下来,我们需要找到一种算法,可以根据给定的5个的和值反推回原abc。这个算法可以在程序中实现。关键是将原问题转化为一个可以求解的学问题。 我们可以将5个的和值表示为: s = (a + b + c) * 3 + (a * 100 + b * 10 + c) + (a * 100 + c * 10 + b) + (b * 100 + a * 10 + c) + (b * 100 + c * 10 + a) + (c * 100 + a * 10 + b) + (c * 100 + b * 10 + a) 化简后得到: s = 222 * (a + b + c) + 101 * (a + b + c) 我们可以发现,s可以被222整除,而101是素,所以a+b+c的取值只能是12、15、18、21、24、27、30、33、36、39、42、45、48、51、54、57、60、63、66、69、72、75、78、81、84、87、90、93、96或99。计算s/222可以得到a+b+c的值,然后枚举a、b、c的所有可能排列,找到符合要求的即可。如果找不到符合要求的,就说明观众算错了。 在程序中,可以预处理出所有符合要求的三位abc和它们的和值s,然后在用户输入和值后查表即可。 以下是Python的程序实现: available_nums = [] for abc in range(100, 1000): a, b, c = abc // 100, (abc // 10) % 10, abc % 10 s = (a + b + c) * 3 + abc + a * 100 + c * 10 + b + b * 100 + a * 10 + c + c * 100 + a * 10 + b if 911 <= s <= 2289: available_nums.append((abc, s // 222)) while True: s = int(input("请输入计算的和值:")) possible_abc = [abc for abc, sum_abc in available_nums if sum_abc == s / 222] if len(possible_abc) == 0: print("你算错了!") elif len(possible_abc) == 1: print("你是:", possible_abc[0]) else: print("有多个可能的答案:", possible_abc) ### 回答3: 这个数字魔术游戏的背后,其实是一道学题。 首先,观众心里的三位abc,可以表示为100a+10b+c。 然后,五个acb、bac、bca、cab、cba的和值为: acb+bac+bca+cab+cba = 222(a+b+c) + 22(b+c+a) + 2(a+c+b) = 246(a+b+c) 因此,如果观众说出和值v,那么a+b+c=v/246,为整,且abc可以表示为: 100(a+b+c) - 99a - 9b = 91(a+b+c) - (7a+b) 因此,只需要枚举a和b的所有可能取值(注意,根据观众说出的和值,a+b+c也有可能超过9),就可以确定唯一的一个解。 以下是Python实现代码: ```python def guess_number(sum): for a in range(1, 10): for b in range(10): if (sum - 7 * a - b) % 91 == 0: c = (sum - 7 * a - b) // 91 if c >= 0 and c <= 9: return 100 * a + 10 * b + c return -1 # 如果没有合法的解,返回-1 # 测试样例 print(guess_number(1999)) # 输出443 print(guess_number(1998)) # 输出-1,即没有合法解 ``` 其中,sum为观众说出的和值,guess_number函返回观众心里的原abc。如果没有合法的解,则返回-1。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值