拿扑克牌问题:
一个有趣的抽扑克牌问题:54张扑克牌,两人轮流拿牌,每人每次最少拿1张牌,最多拿4张牌。谁拿最后一张牌谁输。编写计算机先拿牌必胜的方法。
这个问题我们可以这样考虑:到达最后一轮时,当机器拿完牌时场上只剩下一张牌,这样对手只能拿一张牌,所以必然是机器赢。
简单说明一下思路:到最后一轮时,场上剩下{2,3,4,5}张牌 (表示场上剩下2或3或4或5张牌) 机器必赢,因为时机器每轮先拿牌,拿牌数量又在1~4,所以完全可以控制牌最后只剩下一张。但是如果剩下6张牌,机器是必输的。因为机器拿完牌之后剩下的牌必然在{2,3,4,5},到了对面拿牌,同理对面也可以控制牌只在一张,这样机器必拿最后一张牌。
通过上面这个图可以看见,只要是机器先拿牌,并且每轮场上所剩的牌在左边的区间内,机器是必赢的,因为机器每次拿完牌之后,始终让场上的牌所剩的数量让对面必输。
再分析上面的表格,我们的巧妙的发现,场上的牌如果对5求余为1的话,那么先拿牌的人是必输的。
原理分析:
每轮每个人拿牌的数量都在1~4。也就是两个人一轮拿牌的数量只要其中一个愿意那么就肯定可以控制这轮拿牌的总数量为5。(比如说A拿1张,B只要拿4张就可让这轮牌拿去的总量为5。) 那为什么不是6,3或者其它数字呢?因为后拿牌的人控制不了,规则只允许为1~4张。A拿{1,2,3,4},B只要拿{4,3,2,1}即可。
那知道每轮可以控制拿牌数量为5有什么用呢?如果场上剩余牌数为5的n倍加1(n>=1),比如6,11,16。那么后拿牌的人总是可以控制拿牌数量为5,那么每轮去掉5个。到最后一轮的时候,场上的牌只剩下一个了,又是你先拿牌,所以你必输。
问题和我们刚才分析的刚刚反过来了,问谁先拿必赢。其实原理都是一样的。场上剩下的只要不是5的n倍加1,那么你先拿牌你是必赢的。
代码实现(python)
import random
class DrawCards:
def __init__(self):
self.Cards=54
def machineDraw(self):
while(1):
n=random.randint(1,4)
if (self.Cards-n-1)%5==0:
self.Cards-=n
print('machine draw ',n,'crads')
break
def manDraw(self):
while(1):
n=input('pleasr input a numbee in 1~4\t')
if int(n) in (1,2,3,4):
self.Cards-=int(n)
break
print('error,please enter again')
def Run(self):
count=0
while(self.Cards!=0):
self.machineDraw()
self.manDraw()
count+=1
print('End of round ',count,',there ',self.Cards,'left on the field\n')
if self.Cards in (2,3,4,5):
print('machine draw',self.Cards-1,'cards,you loss!')
break
if __name__ == "__main__":
start=DrawCards()
start.Run()