约瑟夫环问题的解法

约瑟夫环问题的解法

递归法,迭代法,数数法,模拟法

问题描述

Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

有N个人围成一圈,顺序排号。从第一个人开始报数(从 1 到 M 报数),凡报到M的人退出圈子,问最后留下的是原来第几号的那位。

约瑟夫生者死者游戏
约瑟夫游戏的大意:30个游客同乘一条船,因为严重超载, 加上风浪大作,危险万分。因此船长告诉乘客,只有将全船 一半的旅客投入海中,其余人才能幸免于难。无奈,大家只 得同意这种办法,并议定30 个人围成一圈,由第一个人数起,依次报数,数到第9人,便把他投入大海中,然后再从 他的下一个人数起,数到第9人,再将他投入大海中,如此 循环地进行,直到剩下 15 个游客为止。问:哪些位置是将 被扔下大海的位置?

PY代码

# coding=utf-8
from functools import lru_cache
import sys
sys.setrecursionlimit(10**5)  # 设置递归最大深度 10的5次方


@lru_cache(None)
def josephus(n,  m):
    if(n == 1):
        return 0
    else:
        return (josephus(n-1, m) + m) % n


if __name__ == "__main__":
    M, N = 3, 41
    M, N = 9, 30
    M, N = 3, 10
    s = 0
    ans = [0, -1]
    for i in range(2, N+1):
        s = (s+M) % i
        for j in range(len(ans)):
            ans[j] = (ans[j]+M) % i
        if i < N:
            ans.append(-1)
    ans.reverse()
    print(list(i+1 for i in ans), s+1, josephus(N, M)+1)

    ans = []
    live = [True]*N
    i, j = 1, 0
    while any(live):
        if live[j]:
            if i == M:
                live[j] = False
                i = 1
                ans.append(j+1)
            else:
                i += 1
        j += 1
        if j == N:
            j = 0
    print(ans, "true")

    ans = []
    live = list(range(1, N+1))
    i, j = 1, 0
    while (live):
        if i == M:
            i = 1
            ans.append(live[j])
            del live[j]
            if j == len(live):
                j = 0
        else:
            i += 1
            j += 1
            if j >= len(live):
                j = 0
    print(ans, "del")

    ans = [-1]*N
    for i in range(1, N+1):
        for j in range(i):
            ans[j] = (ans[j]+M) % i
    ans.reverse()
    print(list(i+1 for i in ans), "累加ALL")

    firstL = 6
    ans = [-1]*N
    lefts = N-firstL
    for i in range(lefts, N+1):
        for j in range(lefts, i):
            ans[j] = (ans[j]+M) % i
    ans.reverse()
    print(list(i+1 for i in ans), "取前-1")

    ans = [0]*N
    lefts = N-firstL
    for i in range(lefts, N+1):
        for j in range(lefts, i):
            ans[j] = (ans[j]+M-1) % i+1
    ans.reverse()
    print(ans, "取前0")

    ans = [0]*N
    lastN = 4
    for i in range(0, N+1):
        for j in range(0, i if i < lastN else lastN):
            ans[j] = (ans[j]+M-1) % i+1
    print(ans, "LastXu")

结果显示

[3, 6, 9, 2, 7, 1, 8, 5, 10, 4] 4 4
[3, 6, 9, 2, 7, 1, 8, 5, 10, 4] true
[3, 6, 9, 2, 7, 1, 8, 5, 10, 4] del
[3, 6, 9, 2, 7, 1, 8, 5, 10, 4] 累加ALL
[3, 6, 9, 2, 7, 1, 0, 0, 0, 0] 取前-1
[3, 6, 9, 2, 7, 1, 0, 0, 0, 0] 取前0
[4, 10, 5, 8, 0, 0, 0, 0, 0, 0] LastXu

递归法,迭代法,数数法,模拟法

及求前后单独序列的方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值