版权声明:本文为博主原创文章,未经博主允许不得转载。 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))