上一个魔术算是应用约瑟夫原理入门级别的作品,只是用上罢了。前面说了,约瑟夫过程在扑克牌叠上只是一个复杂但又确定的操作过程,应用时候一方面要防止枯燥无聊,另一方面最好再结合一切其他的魔术或数学方法一起使用,才能锦上添花,画龙点睛,发挥这个原理的最大作用。
下面这个魔术,是用约瑟夫原理魔术中,经典中的经典,没有之一,经过一些改编,取名为《自我匹配的奇迹》。
自我匹配的奇迹
视频1 自我匹配的奇迹
这个魔术为观众所熟悉的原因有点特别。作为一个几近完美的自动化魔术,在2016年天猫双十一晚会上,马云当着全世界观众的面表演了这个魔术,不得不佩服马云同学的感知力,学习力,和对包括魔术在内的世界的好奇。
我第一次看到的时候,也是惊诧于这这个自动化流程的精妙。在繁复的操作和随机体验的赋予中找到了完美的平衡。后来在Woody Arogon的教学Woodyland中找到了原版,以及其中的一些变种。到我这里,我依据其基本原理,又做了一些少许改良,在探索基本原理和作魔术改良过程中,一度还遇到了不少困难,尤其数学部分,直到使用了合适的数学工具才解决。比如,我虽然知道取余数,取模这等操作,但并没有把它当作其实和正常四则运算同等地位的运算来理解,而是以别扭的方式来在错误的基础上打补丁,特例能解决但是并没有解决根本问题,可见研究问题的视角的选择有多么重要。
我把整个流程分成了8个步骤,这一篇我们从数学角度来解析里面的原理,下一篇我们从魔术角度继续剖析。
分步数学原理解析
Step1:将一叠4张的牌从中间撕开后叠在一起。
设原始四张卡片洗完以后的排列是C1,2,3,4,那么撕完以后,Ci,假设变成Ai和Bi,Ci = Ai union Bi。
那么叠在一起的排列是A1,2,3,4,B1,2,3,4,虽然可以任意选择一叠在顶部,不妨设顶叠对应的字母是A,另一个叫B。显然这是个关于元素索引值的有限长周期序列,有f(s[x]) = f(s[(x 4)(mod 8)]),f函数指的是卡片对应的编号,变化规律是个关于平移一个单位这个操作的C4群(周期长度为4)。注意是索引这个性质是有周期性的,他们本身并不是完全相同的一张卡,而是来源于同一张卡的两半,共用了同一个编号。因此,相同的性质是编号,或者叫都属于撕之前的那个两半能够拼起来的那个集合。而最后的魔术效果,本来是编号相同是C4群的性质,又对于平移4个位置这种C4群上等价于幺元的操作而言,是个C2群(整个序列共两个周期),其元素是同一个集合,有共同编号属性的特定元素,在这里也就是两个半边的特定排列,循环群内的排列显然怎么排都是原来那个集合,故可以拼合起来,接口方向,则因为顺序未知而由观众自己调整,却一点也不奇怪,哪怕再来些块也无妨。
Step2:切牌1,2张,以及任意张,任意次。
在《序列周期性与魔术(六)——魔术欣赏与解析续集》等系列中,我们曾介绍过扑克牌叠在切牌操作下的周期性。一方面,对指定的切牌张数牌叠不变,而其他的张数所形成的新牌叠,也具有同样的周期性质。这一点,通过模加法能很容易地证明,本身也是周期性的性质。但是切牌以后,原本每个周期内具有的,他们都是A半边或B半边的性质就消失了,而这本来也是周期在特定相位和周期编号条件下的附加属性,并不在周期性的考虑之中。而每个周期内的序列值也没什么特殊的,其实就是1234组成的环,以各个点为起点的各条排列罢了。
Step3:从顶部拿起3张插入整叠牌中间。
3是重要的数字,插入中间也不是完全没有限制,限制就是,插入以后,原来的第一张还是第一张,最后一张也不变。这就是隐含在这个操作下的不变量,“中间”二字为我们暗中保证了这个性质,为我们所用。
那来看看看这里没有变的具体是什么吧?拿走3张以后的第一张其实是第4张,不变,最后一张其实是第8张不变。观众朋友们,第8和4张之间的差距4是什么呀,正好就是周期的大小啊!换句话说,这两个距离为4的牌恰好是满足跨过周期以后应该索引相等的那两张,也是遍历了以移动4个索引为操作的仅有的两个元素,即来自同一张原牌的两个碎片,即最后能做到匹配效果的那两半。
现在他们被确定地放在了第1和8张。
注:
Step1,2,3在Woody Arogan的教学Woodyland中有一个变体,虽然表演上并不如这个方式好,但也不失为一个很好的数学原理应用。那就是,在第一步撕开以后,把其中一叠翻转以后,两叠再合在一起。这样的结局是,这成了一个每个半张的索引属性对称的牌叠,对本身有对称性的操作,有不变性。但是,这种对称牌叠显然是不能够随便切牌了,那是周期性才有的性质。
即,原牌叠有f(2n - a) = f(a)对任意范围内的索引a成立,那么这个置换g如果满足g(2n - a) = 2n - g(a)对成立,即置换前处在对称未知两个有相同性质的元素置换以后仍然处在对称未知,保持对称性,那么该置换我们说也是对称的,并会保持原序列本身存在的对称性。
比如这里我们取n = 4,是个偶数长度,对称中心不在牌索引位的序列。显然,久违的Reverse(数牌翻转)操作是对称的,其实它在周期序列上操作也不破坏周期性,只不过会得到全新的子周期排列。不过Reverse操作太直白了,有没有更好的?
答案是依次发两叠合起来的操作,也可以是它的逆操作,完美洗牌!!!
天哪,依次发两叠和完美洗牌所构成的置换居然有这等性质,简直惊呆了我的双眼,数学和魔术里,究竟还藏着多少宝藏!!!
这一切的详细说明,都可以用扩展的序列操作表达式来表达。这里先不展开,后面有专门章节来讲解。
所以,在这一变体的Step2中,可以随意采用发两叠合起来和完美洗牌来弄乱牌,当然如果是观众自己做,就让他发两叠合起来若干次到满意为止就好了。虽然这个方案并不如原方案直接,但也是十分地美妙!你看,所谓的对称和周期,无非就是同样对象的重复:对称一般是两个部分,而当循环恰好也是两个周期的时候,通过翻转操作,周期循环直接变成对称!甚至,当循环的周期内本身就是对称的,翻转不改变自己的话,那就可以同时拥有对称和周期性了!
还有,这里通过镜面来做还有一个附加的好处,那就是现在牌叠里会有正有反,交错出现,使得混乱度增加,观众更加会认为这是一些乱七八糟随机的结果。
这样完成以后,由于是镜面的对应,因此,此时不需要再做插入3张的操作,天然地现在的顶牌第1张和底牌第8张就是对应的,也是我们最后效果的由来了。
Step4:把第1张牌自己藏起来,先不要看,然后剩下的牌和旁边的同学进行交换。
这一步不需要建模,是纯魔术包装,最后反正匹配的也是自己藏起来的牌和对方的牌叠剩下的牌,把你哥口袋理解成他的口袋就行了,其实就是自己匹配自己。
Step5:接下来,每次从顶上拿起两张,可以任意选一张扔掉,或者啥都不扔,把剩下的放在牌底,一共三次。
这一步是我对原流程比较大的改动之处。这里本质上其实是这7张牌,保持目标牌在底部,然后可以扔掉0~3一共4个选项这么多张牌都可以,只要不扔第7张。原版的做法自然是直接让观众选择1或2张扔掉,当然在这以前还做了一次交换和插入,我的版本里因为有交换了所有这两步就一起省略了,况且插入的过程已经执行过一遍,再做一次也是有被更多地察觉到问题和引入错误的风险的。
那么我就在想,如何让观众在0~3中间选一个数,扔掉这么多张,并且,是任意不包括底牌的他们呢?这里实际的选择总数,考虑不同张数和组合的话,是C(6, 0) C(6, 1) C(6, 2) C(6, 3),有这么多种方法,如果是排列那就把C改成A。一方面,我们要充分利用这个大的自由度,让观众体会到是自己的决定在起作用;另一方面,我们也要使得流程尽量简洁,自然,而没有太多生硬的成分。在原版里面的直接选择顶部1,2张扔掉,相当于只有1bit的信息,这显然太浪费了。但另一个极端,直接拿起顶部6张,让大家随便从中选0~3张扔掉,也显然太刻意了。于是最终我选择了视频中的做法,看起来就是给了3次,每次都有3种选择的机会,log27bit的信息量。而从张数上讲,实际上是给了3个布尔变量供选择,而他们的和恰好范围在0~3了,但不会选到底牌,且可选的张数范围这个变量3bit信息的变量其实完全也没有选择过程看起来的信息自由度大。总之,我的这个改进最大限度地隐瞒了3这个刻意要素,同时也给了观众在可控范围内的最大自由度,同时在限定的操作复杂度范围内。
最后还有一点,那就是,无论怎么扔,因为每次顶部都少两张牌,那么,无意识地3次以后,对于一直没拿到的底牌来说,其索引每次都减少了2,连模都不需要,因为还不曾小于0过,而取模反而和当时的张数有关系,变复杂了。也就是说,原来第7张一定会到第1张,这个确定的隐含事实也是如此设计的关键,它能够让我需要控制位置的牌,仍然在可控位置。
Step6:把整叠牌翻转过来,切牌7次,每次切1张
整叠牌的翻转相当于改变人的观察视角,以至于以此定义的牌叠从原来的底部而不是顶部开始,是一次等效的reverse翻转操作。如果从全序关系来理解排列,相当于是完整的一个倒序,相邻关系的反关系(并不是逆排列)!此时,目标牌位置是倒数第一张,也就是n - 1或者- 1,而整叠牌的张数范围是4~7,也就是7 - 0~3的结果。假设牌的张数是n,这样的7次切牌,使得我们现在关心的底牌位置变为:
(n - 1 - 7) (mod n) = - 8 (mod n)
我们规定,0~(n - 1)为张数位置正向索引,索引从0开始;- 1~- n为逆向索引,从倒数第一张到第0张,而超出范围的牌,也全部在Cn群中等效到相应的0~(n - 1)的完全代表系来表示。
这里,由n的取值范围4~7,最终停留位置为2n - 8。
Step7:对牌叠执行k = 2的约瑟夫过程,直到剩下最后一张。
因为n的范围是4~7,所以n的二进制表示是个3位数,首位为1。末两位恰好是0~3之间数的二位二进制表示,值为(n - 4)。根据前面k = 2的约瑟夫问题公式,其最后一张牌的索引即为2(n - 4),即三位二进制数右移一位的结果。而我们有:
2(n - 4) == - 8 (mod n)
这个位置恰好是我们step6关心的原来的底牌,然后变成顶牌,又变成底牌以后,执行切1张7次的结果。
简直是天衣无缝。我一度在怀疑这到底仅仅是巧合,还是暗含某种特殊的一系列数学结构,当我把n用二进制表达成1b1b2,一切似乎清晰了起来:
7次切牌后底牌的位置:1b1b2 - 1 - 111(mod 1b1b2) == - 8(mod 1b1b2)
约瑟夫的末尾位置:b1b20(mod 1b1b2) == 2 * b1b2 (mod 1b1b2) == 2 * b1b2 - 2 * 1b1b2 = - 8 (mod 1b1b2)
也就是说,当剩余牌的张数的二进制位数为l时候,切l位1的二进制数那么多次,每次1张后,底牌的位置变为- 2 ^ (l 1)(mod n),而约瑟夫的末尾位置的另一个表达也恰好是这个值,其物理意义就是从底牌开始,倒着数到第2 ^ (l 1)那么多张,即为所求。从这里也可以看出k = 2的约瑟夫问题结论的另一种表述和物理意义,其实是这个纯位指数值模的相反数模张数n的结果。
这个推导中,模运算,也就是背后的模加法群的结构起到了至关重要的作用,如果你能看懂但想不到,其实就和我一样,是还不太熟练,至少不如一般的四则运算那么熟练地掌握了他们。懂了它可以突然明白很多事情,比如为什么在程序语言中,负值的索引是从- 1开始,一切都是为了保证在0开始索引和模意义下的等价:- 1 == n - 1(mod n),又比如,整数到底是怎么存储的,搞那些反码补码做什么,范围为什么那么设定,溢出的时候到底发生了什么,以及为什么首位为1的值就是负数等等奇怪的问题了。这个点我们后面会专门讲。
Step8:拿着最后一张,把它和刚才换牌的同学再次交换回来,发现和口袋里的第一个半张完全匹配!
最后,请你拿起扑克牌操作一遍,让我们一起见证数学魔术带给我们的奇迹吧!