Python练习5-函数设计与使用

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()来剔除元素,可见这个方法要比上面两个方法更简单。

总之,它们各有优劣,各有千秋。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值