趣味算法Python实现(四)

1.洗扑克牌(乱数排列)      

        乱数排列,即将一组数字(例如1~N)打乱重新排列,其中洗扑克牌多了花色的判断。

        通常会直接想到,随机产生1~N的乱数并将之存入队列中,随后产生的数字存入队列前必须

先检查队列中是否已有重复的数字,如果有这个数就不存入,再重新产生下一个数,运气不好的

话,重复的次数就会很多,程序的执行速度就会变慢,因此这不是一个好方法。152的乱数排

列为例,可以先依序由152填入,然后使用循环,并随机产生152的数字,将产生的数字当作

索引取出值,并与当前的值相交换,如此就不用担心乱数重复的问题了,队列走访完毕后,所有的

数字也就重新排列了。

实现:
import random
N = 52
poker = [i for i in range(0,N+1)]

for i in range(1,N+1):
    j = random.randint(1, 52)
    tmp = poker[i]
    poker[i] = poker[j]
    poker[j] = tmp

for i in range(1,N+1):
    c = int((poker[i]-1) / 13)
    if c==0:
        print("桃 ",end='')
    elif c==1:
        print("心 ",end='')
    elif c==2:
        print("砖 ",end='')
    elif c==3:
        print("梅 ",end='')

    remain = poker[i] % 13
    if remain == 0:
        print("K ",end='')
    elif remain==12:
        print("Q ",end='')
    elif remain==11:
        print("J ",end='')
    else:
        print("{} ".format(remain), end='')

    if i % 13 == 0:
        print(" ")

2.赌博游戏

        我们设计一个简单的赌博游戏,游戏规则如下:玩家掷两个骰子,点数为1到6,如果第一次

点数和为7或11,则玩家胜,如果点数和为2、3或12,则玩家输,如果和为其它点数,则记录第一

次的点数和,然后继续掷骰,直至点数和等于第一次掷出的点数和,则玩家胜,如果在这之前
掷出了点数和为7,则玩家输。
实现如下:
import random

WON = 0
LOST = 1
CONTINUE = 2

def rollDice():
    i = random.randint(0, 5)
    j = random.randint(0,5)
    return i+j+2

if __name__ == '__main__':
    firstRoll = 1
    gameStatus = CONTINUE
    firstPoint = 0

    print("Craps赌博游戏,按Enter键开始游戏****")
    while True:
        if firstRoll:
            sumOfDice = rollDice()
            print("玩家掷出点数和:{}".format(sumOfDice))

            if sumOfDice==7 or sumOfDice==11:
                gameStatus = WON
            elif sumOfDice==2 or sumOfDice==3 or sumOfDice==12:
                gameStatus = LOST
            else:
                firstRoll = 0
                gameStatus = CONTINUE
                firstPoint = sumOfDice
        else:
            sumOfDice = rollDice()
            print("玩家掷出点数和:{}".format(sumOfDice))
            if sumOfDice == firstPoint:
                gameStatus = WON
            elif sumOfDice == 7:
                gameStatus = LOST

        if gameStatus == CONTINUE:
            print("未分胜负")
        else:
            if gameStatus==WON:
                print("玩家赢")
            else:
                print("玩家输")

            c = input("再玩一次?")
            if c=='n':
                print("游戏结束")
                break
            firstRoll = 1

3.约瑟夫问题

        著名犹太历史学家Josephus 有过以下的故事:在罗马人占领乔塔帕特后, 39个犹太人与
Josephus 及他的朋友躲到一个洞中 39 个犹太人决定宁愿死也不要被敌人到 ,于是决定了一个自
杀方式, 41 个人排成一个圆圈,由第 1 个人 开始报数,每报数到第 3 人该人就必须自杀,然后再由
下一个重新报数,直到所有人都自杀身亡为止。然而 Josephus 和他的朋友并不想遵从, Josephus
要他的朋友先假装遵从,他将朋友与自己安排在第 16 个与第 31 个位置,于是逃过了这场死亡游
戏。
        约瑟夫问题可用代数分析来求解,假设现在您与m个朋友不幸参与了这个游戏,您要如何保护
您与您的朋友?起始只要画两个圆圈就可以让自己与朋友免于死亡游戏,这两个圆圈内圈是排列顺
序,而外圈则是自杀顺序。使用程序来处理,即循环内圈从1到41,每三个数计入,知道技术达到
41为止,即得到自杀顺序,这就是约瑟夫排列,41个人的约瑟夫排列约为:
14 36 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23
由上可知,最后一个自杀的是在第 31 个位置,而倒数第二个自杀的要排在第 16个位置,之前的人
都死光了,所以他们也就不知道约琴夫与他的朋友并没有遵守游戏规则了。
实现如下:
N = 41
M = 3
man = [0]*N
count = 1
pos = -1
alive = 0
i = 0
while count<=N:
    while True:
        pos = (pos+1) % N
        if man[pos] == 0:
            i += 1
        if i==M:
            i = 0
            break

    man[pos] = count
    count += 1

print("约瑟夫排列")

for i in range(0,N):
    print('{} '.format(man[i]),end='')

alive = 2

for i in range(0,N):
    if man[i] > alive:
        print("D ",end='')
    else:
        print("L ",end='')
    if (i+1) % 5 == 0:
        print(" ")

4.排列组合

        将一组数字、字母或符号进行排列,以得到不同的组合顺序,例如1 2 3这三个数的排列组合

有:1 2 3、1 3 2、2 1 3、2 3 1、3 1 2、3 2 1。

        最容易想到的方法是使用递回将数字切割为较小的单元进行排列组合,例如1 2 3 4 的排列可
以分为1 [2 3 4] 2 [1 3 4] 3 [1 2 4] 4 [1 2 3] 进行排列。这里我们使用旋转法,先将旋转间隔设
0,将最右边的 数字旋转至最左边,并逐步增加旋转的间隔。
实现如下:
N = 4
def perm(num, i):
    if i<N:
        for j in range(i,N+1):
            tmp = num[j]
            for k in reversed(range(i+1,j+1)):
                num[k] = num[k-1]
            num[i] = tmp
            perm(num, i+1)
            for k in range(i, j):
                num[k] = num[k+1]
            num[j] = tmp
    else:
        for j in range(1,N+1):
            print("{} ".format(num[j]),end="")
        print(" ")

if __name__=="__main__":
    num = []
    for i in range(0,N+1):
        num.append(i)
    perm(num, 1)

5.格雷码

        Gray Code是一个数列集合每个数使用二进位来表示假设使用n位来表示每个数,任两个

数之间只有一个值不同,例如以下为3位元的Gray Code

000 001 011 010 110 111 101 100
由定义可以知道, Gray Code 的顺序并不是唯一的,例如将上面的数列反过来写,也是一组 Gray
Code
100 101 111 110 010 011 001 000
Gray Code 是由贝尔实验室的 Frank Gray 1940 年代提出的,用来在使用 PCM Pusle Code
Modulation )方法传送讯号时避免出错,并于 1953 年三月十七日取得美国专利。

这里我们使用代码来计算Gray Code,由于Gray Code相邻两数之间只改变一个位元,所以可观 察

Gray Code从1变0或从0变1时的位置,假设有4位元的Gray Code如下:

0000 0001 0011 0010 0110 0111 0101 0100
1100 1101 1111 1110 1010 1011 1001 1000
观察奇数项的变化时,我们发现无论它是第几个 Gray Code ,永远只改变最右边的数字,如果
1 就改为 0 ,如果是 0 就改为 1。观察偶数项的变化时,我们发现所改变的数字,是由右边算来第
一个1的左边。以上两个变化规则是固定的,无论位置为何;所以只要判断是奇数还是偶数,
就可以决定要改变哪一个数字的值,将 2 位的 Gray Code当作平面座标来看,可以构成一个四边
形,您可以发现从任一顶点出发,绕四边形周长绕一圈,所经过的顶点座标就是一组 Gray Code
所以您可以得到四组Gray Code。同样的将 3 位元的Gray Code当作平面座标来看的话,可以构成
一个正立方体,如果您可以从任一顶点出发,将所有的边长走过,并不重复经过顶点的话,所经过
的顶点座标顺序之组合也就是一组 Gray Code
实现如下:
MAXSIZE = 20

digit = []

n = 3
for i in range(n):
    digit.append('0')

print('{} ')

while True:
    i = 0
    while i < n and digit[i] == '1':
        digit = '0'
        i += 1

    if i == n:
        break
    else:
        digit[i] = '1'

    i = 0
    while i < n and digit[i] == '0':
        i += 1

    print("{{} ".format(i+1), end='')

    for j in range(i+1,n+1):
        if digit[j] == '1':
            print(',{}'.format(j+1),end='')

    print('}')

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苜蓿花乐园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值