算法 · 2024年2月17日 2

刘谦春晚魔术

在力扣上看见有两个老哥分享了春晚刘谦魔术的模拟实现和代码实现, 参考他们的文章后写了此文
参考文章: https://leetcode.cn/circle/discuss/hzkbAV/

  • 简单叙述魔术过程
  1. 打乱扑克牌顺序 抽四张牌 (ABCD)
  2. 对折撕成两半 将一堆放在另一堆派底 (ABCDabcd)
  3. 名字几个字就将牌顶的一张牌放到牌底 (DabcdABC)
  4. 拿起最上面三张 插进牌堆中间(此时最上面和最下面的牌是相同的) (cdADabBC)
  5. 拿起最上面一张 放在一旁 (dADabBC)
  6. 南方人从牌顶拿起一张 北方人拿两张 不确定南北方人拿三张 插到牌堆中间 (DabdABC)
  7. 男生从上面拿一张 女生拿两张扔掉 (abdABC bdABC)
  8. s=len("见证奇迹的时刻") 将 s 张牌从牌顶放到派底 (bdABCa ABCbd)
  9. 循环: 一张从牌顶放牌底 下一张丢掉 直到还剩一张牌 (C)
  10. 这张牌和旁边的牌是相同的 (C=c)

注: 解释一下插入牌堆中间的操作, 比如有三张牌, 那么中间位置就有两个, 分别是第一, 第二张牌之间以及第二, 第三张牌之间

  • py 代码

    名字, 南北方人, 男女生区别在代码中写死
    随即插入牌堆中间通过随机函数 random.randint 实现

# 抽四张牌 对折撕成两半 将一堆放在另一堆派底
s = 'ABCDabcd'
print('抽四张牌 对折撕成两半 将一堆放在另一堆派底: ' + '\n' + s)

# 名字几个字就将牌顶的几张牌放到牌底
nameLen = 3 % len(s)
t = ''
t=s[nameLen:]+s[:nameLen]
print('名字几个字就将牌顶的几张牌放到牌底: ' + '\n' + t)

# 拿起最上面三张 插进牌堆中间
temp, origin = t[:3], t[3:]
r = random.randint(1, len(origin)-1)
t = origin[:r]+temp+origin[r:]
print('拿起最上面三张 插进牌堆中间: ' + '\n' + t)

# 拿起最上面一张 放在一旁
ans_1 = t[0]
t = t[1:]
print('拿起最上面一张 放在一旁: ' + '\n' + t)

# 南方人从牌顶拿起一张 北方人拿两张 不确定南北方人拿三张 插到牌堆中间
areaNum = 2
temp, origin = t[:areaNum], t[areaNum:]
r = random.randint(1, len(origin)-1)
t = origin[:r]+temp+origin[r:]
print('南方人从牌顶拿起一张 北方人拿两张 不确定南北方人拿三张 插到牌堆中间: ' + '\n' + t)

# 男生从上面拿一张 女生拿两张扔掉
sexNum = 1
t = t[sexNum:]
print('男生从上面拿一张 女生拿两张扔掉: ' + '\n' + t)

# 将7张牌从牌顶放到派底 (s=len("见证奇迹的时刻"))
n = len("见证奇迹的时刻") % len(t)
t = t[n:] + t[:n]
print('将7张牌从牌顶放到派底 (s=len("见证奇迹的时刻")): ' + '\n' + t)

# 循环: 一张从牌顶放牌底 下一张丢掉 直到还剩一张牌
while(len(t) > 1):
    t = t[1:] + t[:1]
    t = t[1:]
print('结果是: ')
print(t + "=" + ans_1)
  • 代码执行结果

  • 实验总结

根据实验结果我们可以看到, 执行"拿起最上面三张牌插入牌堆中间"操作后, 牌堆最上面和最下面的牌是一张牌, 随后将最上面的牌放在一旁后, 后面的操作只要把另一张牌保留到最后就可以了.
小尼失败是因为没有将三张牌插进牌堆中间, 插进牌堆最后导致牌底与藏起来那张不是同一张了.