约瑟夫环 Python&Swift实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012505432/article/details/51747181

Josephus问题的通解公式是
f(n,k)=((f(n-1,k)+k-1) mod n)+1,f(1,k)=1
其中f(n,k)表示n个人玩约瑟夫杀人游戏,每次报号k倍数的人被干掉的规则下最终剩下的那个人原本的标号。

假设有10个人,即n = 10,

0 1 2 3 4 5 6 7 8 9 选择 m = 3

那么第一个人出列后的序列为:

0 1 3 4 5 6 7 8 9 ,即:

3 4 5 6 7 8 9 0 1 (i)我们可以将该式转换为:

0 1 2 3 4 5 6 7 8 (ii)

那么则有 ((ii)+ 3 )% 10 = (i)

也就是说,我们求出九个人中第9次的编号,利用上式进行转换就能得到第10个人第10次的结果。

进行普遍情况的分析:

n个人(编号0…n-1),从0开始报数,报到m-1的出列,剩下的n-1个人继续从0开始报数,求胜利者的编号。

、第一个出列的人编号一定是 m%n-1, 剩下的n-1个人组成一个新的约瑟夫环(以编号为k=m%n的人开始):

原始 k k+1 k+2 n-2 n-1 0 1 2 k-2
新环 0 1 2 n-1

变换后就完全变成n-1个人报数的子问题。

假设子问题的解为x,那么根据上面这个表把x变为相应的n个人的情况。也就是求目前为x的人在n个人情况是标号为多少。x’=(x+k)%n。

同理,知道n-2个人可以推出n-1个人,知道n-3个人可以推出n-2个人….

令f[i]表示第i个人玩游戏报m退出最后胜利者的编号,最后的结果为f[n]

递推公式:

f[1] = 0

f[i] = (f[i-1] + m) % i (i>1)

因为实际生活中编号总是从1开始,我们输出f[n] + 1。

swift程序如下:

import UIKit
//实现约瑟夫环
func Josephus(total:Int, out:Int) -> Int{
    let n = total
    let m = out
    var temp = 0    //初始化f[1] = 0
    for i in 1...n {
        temp = (temp + m) % i     //f[i] = (f[i-1] + m) % i
    }
    return temp + 1
}
let liveMan = Josephus(6, out: 2)
//output:5

Python代码:

def Josephus(total, out):
    n = total; m = out
    temp = 0
    for i in range(1, n+1):
        temp = (temp + m) % i     #f[i] = (f[i-1] + m) % i
    return temp + 1

print(Josephus(6, 2))

猜你喜欢

转载自blog.csdn.net/u012505432/article/details/51747181