尤拉計劃622:洗牌

lt發表於2020-01-23

一副牌被分成兩等分,上半疊在左手,下半疊在右手。接下來,卡被完全交錯,右半部的最上卡正好插在左半部的最上卡之後,右半部的第二張卡正好插在左半部的第二張卡之後,等等(注意這個過程保留了牌組上下卡的位置)
令s(n)是大小為n的牌組恢復其原始配置所需的最小連續重複洗牌次數,其中n是一個正偶數。
令人驚訝的是,一副52張牌的標準撲克只要完全洗8次牌將就會返回到原來的配置,所以s(52)=8
可以證實一個86張牌的牌組也會在洗8次牌後恢復到原來的配置 。
滿足s(n)=8的所有n值之和s(n)=412
求滿足s(n)=60的所有n值之和

下面的簡單程式可以測試

def sf(x):
 return [ x[:len(x)//2][i] if j%2==0 else x[len(x)//2:][i] for i in range(0,len(x)//2) for j in range(2)]

def test(n):
 c=0
 x=list(range(1,n+1))
 xm=[i for i in x]
 while True:
  c+=1
  xm=sf(xm)
  if x==xm:return c    

>>> test(52)
8
>>> test(84)
82
>>> test(86)
8
>>> [i for i in range(2,300,2) if test(i)==8]
[18, 52, 86, 256]
>>> sum([i for i in range(2,300,2) if test(i)==8])
412
>>> [i for i in range(2,300,2) if test(i)==60]
[62, 144, 176, 184, 226, 288]

通過分析每輪洗牌後牌的變化,相鄰兩牌的間隔從n/2開始,每次間隔都縮小1半,如果遇到奇數,則加上n-1之後再縮小,一直下去到間隔等於1之後就恢復原狀了。因此得到如下快一點的版本

def gen(x):
 n=x
 c=0
 while n>1:
  if n%2==0:n//=2 ;c+=1 #;print(n)
  else: n+=(x-1)
 return c

def s(n):
 return [i for i in range(2,2**n+1,2) if gen(i)==n]

>>> s(12)
[14, 36, 40, 46, 66, 92, 106, 118, 196, 274, 316, 456, 586, 820, 1366, 4096]
>>> s(13)
[8192]
>>> s(14)
[44, 130, 382, 5462, 16384]

相關文章