1、某商场用轮盘抽奖,轮盘的[0°, 30°)对应一等奖, [30°, 108°)对应二等奖,[108°, 360°)对应三等奖。使用 0~360 的随机数表示消费者转动轮盘后指针所处的位置。编写程序,模拟该游戏,并试玩 10000 次,记录每个奖项的中奖次数。
import random
# 模拟轮盘抽奖
def fun(n):
firstPrize=0
secondPrize=0
thirdPrize=0
for _ in range(n):
x=random.randint(0,360)
if 0<=x<30:
firstPrize+=1
elif 30<=x<108:
secondPrize+=1
else:
thirdPrize+=1
return firstPrize,secondPrize,thirdPrize
firstPrize,secondPrize,thirdPrize=fun(10000)
print('一等奖的中奖次数为',firstPrize)
print('二等奖的中奖次数为',secondPrize)
print('三等奖的中奖次数为',thirdPrize)
2、抓狐狸小游戏。假设共有 5 个洞口,小狐狸在其中一个洞口,然后玩家随机打开一个洞口。抓到则成功,失败则重新抓。但是狐狸会在玩家重抓之前跳到隔壁洞口里。如果在规定的次数内抓到了狐狸则游戏成功;否则失败。
import random
# 抓狐狸
def Grap(n):
fox=random.randint(1,5)
for i in range(n):
print(f'抓狐狸第{i+1}次:')
# 玩家随机打开一个洞口(如果知道狐狸会跳到隔壁洞口里,可以据此操作的话,应该进行优化,但这对狐狸不公平)
x=random.randint(1,5)
if x==fox:
print(f'抓狐狸成功!({x},{fox})')
break
else:
print(f'({x},{fox})重新抓')
# 狐狸随机跳到隔壁洞口里
rand=random.randint(0,1)
if rand==1 and fox<=4 or rand==0 and fox==1:
fox+=1
else:
fox-=1
else:
print('抓狐狸失败!')
n=eval(input('请输入规定的抓捕最大次数:'))
Grap(n)
3、假如你在参加一个游戏节目,前方有 3 道门可以选择,其中一个门后面是汽车,另外两个门后面是山羊。主持人知道每个门后面是什么。你选择一个门,例如1号门,这时主持人打开了另一个门(例如 3 号门,后面是一只山羊),并你:“你想改选 2号门吗?”,然后根据你的选择确定最终要打开的门,并确定你获得山羊(输)或者汽车(赢)。编写程序,模拟上面的游戏。
import random
def Choice():
s={1,2,3}
# 在某个门后有一辆汽车
car=random.randint(1,3)
# 你选择一个门
x=eval(input('请选择一个门(1,2,3):'))
# 主持人打开了另一个门,后面是一只山羊
host=s-{x}-{car}
if len(host)==2:
index=random.randint(0,1)
else:
index=0
h=list(host)[index]
print(f'主持人打开了{h}号门')
# 是否改选
for i in s:
if i!=x and i!=h:
y=i
break
print(f'你想改选{y}号门吗?')
x=eval(input('请最终选择一个门(1,2,3):'))
if x==car:
print('你获得汽车(赢)')
else:
print('你获得山羊(输)')
print(f'(你选择了{x}号门,主持人打开了{h}号门,汽车在{car}号门)')
Choice()
4、假设一段楼梯共15个台阶,小明一步最多能上3个台阶。编写程序计算小明上这段楼梯一共有多少种方法。要求给出递推法和递归法两种代码。
# 递推法
def ways_up_1(step):
steps=[0]*(step)
# 确定第一、二、三个台阶走法
steps[0]=1
steps[1]=2
steps[2]=4
# 在第n>3台阶,走法是前一个n-1台阶走法加上走一步+前两个n-2台阶走法加上走两步+前三个n-3台阶走法加上走三步
for i in range(3,step):
steps[i]=steps[i-1]+steps[i-2]+steps[i-3]
return steps[step-1]
# 递归法
def ways_up_2(step):
# 确定第一、二、三个台阶走法
steps=[1,2,4]
if step<4:
return steps[step-1]
# 在第n>3台阶,走法是前一个n-1台阶走法加上走一步+前两个n-2台阶走法加上走两步+前三个n-3台阶走法加上走三步
else:
return ways_up_2(step-1)+ways_up_2(step-2)+ways_up_2(step-3)
step=15
print('(递推法)走法:',ways_up_1(step))
print('(递归法)走法:',ways_up_2(step))
5、尼姆游戏: 两个玩家轮流从一堆物品中拿走一部分。在每一步中,玩家至少拿走一个并且最多只能拿走一半物品,然后轮到下一个玩家。拿走最后一个物品的玩家输掉游戏。在聪明模式中,计算机每次拿走一定数量的物品使得堆的大小是 2 的幂次方减1, 也就是 3、 7、 15、 31、 63 等。如果有一定数量的剩余物品, 计算机就随机拿走一些。 编写程序,模拟聪明版本的尼姆游戏。
import random
from math import log2
# 模拟聪明版本的尼姆游戏
def nimu(n):
flag=True
cnt=1
while flag:
print(f'===========round {cnt}===========')
a=random.randint(1,n//2)
n-=a
print(f'玩家a拿了{a},剩余{n}')
if n==1:
print('玩家b输了!')
break
# 拿走一定数量的物品使得堆的大小是 2 的幂次方减1
for i in range(1,n//2+1):
if log2(n-i+1)%1==0:
n-=i
print(f'玩家b拿了{i},剩余{n}')
if n==1:
print('玩家a输了!')
flag=False
break
# 剩余物品足够多,随机拿
else:
b=random.randint(1,n//2)
n-=b
print(f'玩家b拿了{b},剩余{n}')
if n==1:
print('玩家a输了!')
flag=False
cnt+=1
n=eval(input('请输入物品数量:'))
nimu(n)
也可以采用人机交互:
import random
from math import log2
# 模拟聪明版本的尼姆游戏
def nimu(n):
nHalf=n//2
# 拿走一定数量的物品使得堆的大小是2的幂次方减1
for i in range(1,nHalf+1):
if log2(n-i+1)%1==0:
return i
# 剩余物品足够多,随机拿
else:
return random.randint(1,nHalf)
n=eval(input('请输入物品数量:'))
nHalf=n//2
cnt=1
while True:
print(f'===========round {cnt}===========')
while True:
try:
a=eval(input(f'请玩家输入物品数量[1,{nHalf}]:'))
except:
print('输入错误,请重新输入!')
continue
if type(a)== int and 1<=a<=nHalf:
break
else:
print('输入错误,请重新输入!')
n-=a
nHalf=n//2
print(f'玩家a拿了{a},剩余{n}')
if n==1:
print('玩家b输了!')
break
b=nimu(n)
n-=b
nHalf=n//2
print(f'玩家b拿了{b},剩余{n}')
if n==1:
print('玩家a输了!')
break
cnt+=1
在实验后我发现,如果玩家先手,只要物品数量为偶数,采用聪明模式,就可以击败后手的电脑^_^。
6、 有A,B,C 3 个底座 , A座上有 64个盘子,且大小不等, 所有底座上要求: 大的 在下,小的在上。把这 64 个盘子从 A 座移到 C座,可以利用 B座,每次只能允许 移动一个盘子。 编写函数,接收一个表示盘子数量的参数和分别表示源、目标、临 时底座的参数,然后输出详细移动步骤和每次移动后 3 个底座上的盘子分布情况。
def hanNuo(n,src,dest,temporary):
global cnt
if n==1:
# 将最后的一个盘子从源转移到目标后结束函数调用
cnt+=1
print(f"{cnt}:将盘子从{src}转移到{dest}。")
else:
# 先将n-1个盘子从src移到temporary
hanNuo(n-1, src, temporary, dest)
# 再将src的最后1个盘子从移到dest
hanNuo(1, src, dest, temporary)
# 最后将n-1个盘子从temporary移到dest
hanNuo(n-1, temporary, dest, src)
cnt=0
n=eval(input('请输入盘子数量:'))
hanNuo(n, 'A', 'C', 'B')
7、有n个人围成一圈, 从1开始按顺序编号, 从第一个人开始从1到(假设k=3)报数,报到k的人退出圈子; 然后圈子缩小, 从下一个人继续游戏, 问最后留下的是原来的第几号。编写程序, 模拟上面的游戏, 要求初始人数 n 和报数临界值 k 可以自由指定。运行程序并观察游戏进行的过程。使用两种方法实现, 并简单分析其优劣。
方法1:
def baoshu_1(n,k):
num=[ i for i in range(1,n+1)]
length=len(num)
index=0
cnt=0
while True:
if length==1:
return num[0]
else:
# 开始报数,报到k的退出,剩下的接着重新报,若报到尾则循环从头报。
# 若都报了一遍还没报到k,则重新进入while循环继续报,直到留下最后一个为止。
for i in range(index,length):
cnt+=1
if cnt==k:
print(f'{num[i]}号退出圈子')
num.remove(num[i])
cnt=0
length=len(num)
if i>=length:
index=0
else:
index=i
break
else:
for i in range(index):
cnt+=1
if cnt==k:
print(f'{num[i]}号退出圈子')
num.remove(num[i])
cnt=0
length=len(num)
if i>=length:
index=0
else:
index=i
break
n=eval(input('请输入n:'))
k=eval(input('请输入k:'))
num=baoshu_1(n,k)
print(f'最后留下的是{num}号')
方法2:
def baoshu_once(num,k):
# 开始报数,报到k的退出,剩下的接着重新报,若报到尾则循环从头报。
# 若都报了一遍还没报到k,则重新进入while循环继续报,直到留下最后一个为止。
cnt=0
l=len(num)
while True:
for i in range(l):
cnt+=1
if cnt==k:
print(f'{num[i]}号退出圈子')
num.remove(num[i])
l=len(num)
flags=[False]*l
if i>=l:
flags[0]=True
else:
flags[i]=True
return flags
def baoshu_2(n,k):
num=[ i for i in range(1,n+1)]
while True:
flags=baoshu_once(num,k)
if len(num)==1:
print(f'最后留下的是{num[0]}号')
return
num1=[]
length=len(num)
f=False
for i in range(length):
if flags[i]:
f=True
if f:
num1.append(num[i])
else:
for i in range(length-len(num1)):
num1.append(num[i])
num=num1
n=eval(input('请输入n:'))
k=eval(input('请输入k:'))
num=baoshu_2(n,k)
方法3:
def josephus(n,k):
# 创建人员列表
people = list(range(1, n+1))
# 初始化索引和报数计数器
index = 0
cnt = 0
while len(people) > 1:
cnt += 1
# 报数到k时淘汰当前人员
if cnt == k:
print(people[index],'号淘汰')
# pop参数是索引(remove参数是元素)
people.pop(index)
cnt = 0
else:
index = (index + 1) % len(people)
# 返回最后留下的人的编号
return people[0]
n=7
k=3
res = josephus(n,k)
print(f"最后留下的是{res}号")
可见,上述三个个方法结果一致。
方法1利用index来标记退出位置,用cnt来报数,利用for...else...产生环路,利用while...来解决报数人数少于报数k的情况。
方法2利用flags来标记退出位置,用cnt来报数,利用while...产生环路和解决报数人数少于报数k的情况,利用num1来刷新num,使得在baoshu_once函数中可以使用for i in range(l)从头遍历。
方法3利用index标记列表索引,用cnt来报数,利用pop()来剔除元素,可见这个方法要比上面两个方法更简单。
总之,它们各有优劣,各有千秋。