python解决约瑟夫问题

约瑟夫问题:

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

1. 方法一

Code:

list1 = [i for i in range (1 , 42)]
# print(list1)
ls = []
while True:
    ls.append (list1[2])
    list1 = list1[3::] + list1[0:2:]
    # print(list1)
    if len (list1) == 2:
        break
print (ls)   # 输出 [3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 1, 5, 10, 14, 19, 23, 28, 32, 37, 41, 7, 13, 20, 26, 34, 40, 8, 17, 29, 38, 11, 25, 2, 22, 4, 35]
print(list1)  # 输出 [16, 31]

解决约瑟夫问题的方法有许多种,在数据结构中,大部分都是用循环链表来解决约瑟夫问题的,太复杂不会,这里刚开始思考是分片操作拿出满足的数,然后删除这个数,将列表后再加一个列表,可是这会改变列表的索引,随着循环的次数增加,根本无法写出满足要求的算式,后来搜索找到另一个思路,只需要取出第n个需要的数,然后以这个数将列表拆开,将n之后的列表和n之前的列表组装成一个新的列表,如此只需循环下去便可得到需要的数,当列表的长度不满足再进行重组列表操作时,但是当剩下的数小于n的时候,系统就会执行不了,因为数不到n,所以说这种方法还不是很好的,如果不是数3,而是数9 ,10 比较大的,就会留下很多数.

2.方法二

Code:

list1 = [i for i in range (1,42)]
n = 1
a = 0
while len (list1) > 0:
    if n == 3:
        n = 1
        print (list1[a],end=',')
        list1.pop (a)
    else:
        n += 1
        a += 1
    if a == len (list1):
        a = 0

这一种方法使用两个变量进行控制,一个变量控制计数,每数到3的时候变成1重新数,同时输出并删除掉这个数,另一个变量控制着列表的索引,当循环走到列表结束时,赋值为0 ,意味着从列表头部重新开始循环,两个变量互不干扰,这样就可以一直循环下去,列出所有人的死亡顺序,一步到位.当然这个思路也可以用于字典,将列表换成字典,key为每个人的数字,从1开始,value都设为一,思路同上,只不过并不是删除元素,而是更改value为0,然后加个判断,如果循环到value为0的键,将控制键的变量加1 后继续下次循环判断,因为这里没有删除,所以判断value为0后仍要加1.代码参考如下:

Code:

people = {
     }
for x in range (1,42):
    people[x] = 1

i = 1
j = 0
while i <= 42:
    if i == 42:
        i = 1
    else:
        if people[i] == 0:
            i += 1
        else:
            j += 1
            if j >= 3:
                people[i] = 0
                j = 0
                print (i,end=' ')
            else:
                i += 1

你可能感兴趣的:(python,约瑟夫问题,python)