【100个python算法超详细讲解】@谷歌学术
1.问题描述
由两个人玩“抢30”游戏,游戏规则是:第一个人先说“1”或“1,2”,第
二个人要接着往下说一个或两个数,然后又轮到第一个人,再接着往下说
一个或两个数。这样两人反复轮流,每次每个人说一个或两个数都可以,
但是不可以连说三个数,谁先抢到30,谁得胜。
2.问题分析
首先,分析这个游戏是否公平。一个游戏的公平性主要体现在游戏双
方赢的机会性,如果机会性一样大,就公平,否则就不公平。那么,这个
游戏中两人赢的机会性是不是一样大呢?
经分析可知,获胜者最后总能说到27,还有呢?获胜者陆续说出了
24,21,18,15,12,9,6,3。因此,只要能控制讲出上述数,就一定能
在最后“抢到30”。在大家不知情的情况下,不管先说后说,都有赢的可能
性,但游戏里潜藏着人为可控的必胜因素。还可以发现,失败者报1个数,
获胜者就报2个数;失败者报2个数,获胜者就只报1个数。所以获胜者总能
迅速报数。
结论:如果有人利用数学规律掌握了必胜的秘诀,巧妙设计,就可以
做到每战必赢,这个游戏其实是不公平的。
然后,探究只赢不输的奥秘。
规律1:使用逆推的方法
要想抢到30,必须先抢到27,这样,无论对方说28或“28,29”,自己总
能抢到30。现在问题转换为如何抢到27。要想抢到27,必须先抢到24,这
样,无论对方说25或“25,26”,自己总能抢到27……照此推理下去,要想抢
到6,必须先要抢到3,这样无论对方说4或“4,5”,自己总能抢到6。最后,
问题转换为如何抢到3,要想抢到3,只有让对方先开始,这样无论对方先
说1或“1,2”,自己总能抢到3。由此可见,这个游戏是偏向后开口的人,若
这个人能抢到3,6,9,12,…,21,24,27,则一定会赢,因此,这个游
戏是不公平的。
规律2:使用循环法
根据游戏规则,第一个人可以在1或“1,2”中选择一个或两个数字,对
于“抢30”游戏,第二个人总是可以控制每轮报数的个数为3,由于30可以被3
整除,因此第二个人可以控制自己最后说到30从而获胜。
如果把“抢30”游戏改成“抢50”,可类似地进行分析。要先抢到50,就要
先抢到47,44,41,…,5,2。因此,我们发现,“抢50”的游戏是偏向先开
口的人。
3.Python语言函数介绍
Python语言是函数的语言。对于函数,我们可以从以下几个方面去理解
和把握。
(1)小函数大程序
意思是说,一个Python程序可以很大,但通常是由多个函数组成的。从
这个意义上讲,函数往往就比较短小。
·一个程序需要由几个函数来实现,这取决于用户对Python语言的掌握
程度和领悟能力,没有硬性规定,以方便编程、方便调试和方便升级为原
则。
·一个程序分解成几个函数,有利于快速调试程序,也有利于提高程序
代码的利用率。因为函数是可以多次被调用的,调用次数和调用场合没有
限制。除main()函数以外,任何一个函数都可以调用另外一个函数。
·不要指望通过一个函数就解决程序中的所有问题。事实上,每个函数
都应该做自己最应该做的事情,即每个函数都应该具有相对独立的功能。
(2)main()函数及其作用
·不管是规模很大的Python语言程序,还是比较短小的Python语言程
序,永远都只能有一个而且只能有一个main()函数。
·main()函数可以放在程序中的任何一个地方,可以在程序首部,也可
以在程序中间,还可以在程序尾部。
·在Python语言程序中,不管main()函数放在程序的什么地方,都一定是
从main()函数开始执行程序的,并且从main()函数结束程序。所以,main()
函数又被称为主函数,它是Python程序执行的入口。
(3)函数的种类
函数通常分为模块库函数和自定义函数(用户函数)两大类。
·模块库函数是相应的模块提供的函数,我们可以直接调用。
·自定义函数是指由编程者自己编写的、用以实现特定功能的函数。所
谓编写Python程序或开发Python程序,在很大程度上就是指编写若干个自定
义函数(包括main()函数)。
(4)函数的定义、调用和说明
自定义函数时会涉及3个方面的问题:这个函数的功能及实现方法、如
何来调用及调用前必要的准备。这3个方面分别对应着Python语言中的3个概
念:函数定义、函数调用和函数说明。函数定义最为关键,因为函数必须
要先定义才能使用。
简单地归纳函数定义的语法如下:
def 函数名(函数的参数):
函数体(即函数的具体程序,由若干条语句组成)
更多关于Python函数的知识点,在前面的章节中就已经说过,在此不再
细说。
4.完整的程序
根据上面的分析,编写程序如下:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @author : liuhefei
# @desc: 抢30
import random
# 定义输入函数
def input_num(t):
a = int(input("Please count:"))
while a > 2 or a < 1 or a + t > 30:
if a > 2 or a < 1 or a + t > 30:
print("Error input, again!")
else:
print("You count: %d" % (t + a))
a = int(input("Please count:"))
print("You count: %d" % (t + a))
return t + a # 返回当前已经取走的数的累加和
# 计算谁会胜利
def copu(s):
c = 0
print("Computer count: ", end="")
if (s + 1) % 3 == 0: # 若剩余的数的模为1,则取1
s = s + 1
print(s)
else:
if (s + 2) % 3 == 0:
s = s + 2 # 若剩余的数的模为2,则取2
print(s)
else:
c = random.randint(1, 2) # 否则随机取1或2
s = s + c
print(s)
return s
if __name__ == "__main__":
tol = 0
print("***********catch thirty **************")
print("Game Begin")
# 取随机数决定机器和人谁先走第一步。若为1,则表示人先走第一步
if (random.randint(1, 2) == 1):
tol = input_num(tol)
while tol != 30: # 游戏结束条件
tol = copu(tol)
if tol == 30: # 计算机取一个数,若为30则机器胜利
print("Computer: I lose !")
else:
tol = input_num(tol)
if tol == 30: # 人取一个数,若为30则人胜利
print("People: I lose !")
print("************Game Over********************")
5.运行结果
在PyCharm下运行程序,结果如图7.10所示。
6.拓展训练
已知桌上有25颗棋子,现在要求游戏双方轮流取棋子,每人每次至少
取走一颗棋子,最多可取走3颗棋子。照此取下去,直到将所有棋子取完,
此时必然有一方手中的棋子数为偶数,而另一方手中的棋子数为奇数,规
定偶数方获胜。编程实现此人机游戏。