您的位置:首页 > 其它

Josephus Problem

2013-05-28 17:49 176 查看
问题描述:
n个罪犯被一群人追杀,为了不被敌人杀死,n个罪犯决定通过如下的方式自杀:手拉手围成一圈,并对每个人按顺序编号为:1,2,3,...,n。
从1开始报数,报到k的那个人就自杀,再从自杀的下一个人继续从1开始报数,以此类推,我们能够知道最后幸存的那个人的编号吗?

解决方法:
通过DP能够在$O(n)$解决问题。
首先我们需要递推式:

设$f(n,k)$表示有n个人且报到k的人自杀的情况下,最后幸存的人的编号。

\[f(n,k)=(f(n-1,k)+k - 1)\%n + 1\]

其中 $f(1,k) = 1$。

如果有 $n$ 个人且报到 $k$ 的人自杀时,第一个自杀的人一定是编号为 $(k-1) \% n + 1$ 的人,因此剩下还有$n-1$ 个人,把 $f(n,k)$ 想象成一个子程序,你能够调用它,我们只需要把剩下的 $n-1$ 个人重新编号,就能用 $f(n-1,k)$ 解决了。重新编号如下:

原来的编号 1    2    ...  k-1  k+1    k+2 ...  n
现在的编号 n-k+1  n-k+2     n-1   1     2     n-k

假设现在编号为 $i$,则原来的编号为$(i+k-1) \% n + 1$(注意,这里不是(i+k) mod n,因为当i=n-k时,(i+k) mod n = 0)。

如果按照“现在的编号”的方式,用 $f(n-1,k)$ 能够找到幸存者,因此再将“现在的编号”转换成原来的编号即可,即 $f(n,k)=(f(n-1,k)+k - 1)\%n+1$

另解:如果按照 0,1,2,...,n-1 编号,则递推式变成了:

\[f(n,k)=(f(n-1,k)+k)\%n\]

其中$f(1,k)=0$

代码实现:

public class Josephus {
public static int josephus0(int n,int k){
int r = 0;
for(int i=2;i<=n;i++){
r = (r + k) % i;
}
return r;
}
public static int josephus1(int n,int k){
int r = 1;
for(int i=2;i<=n;i++){
r = (r + k - 1) % i + 1;
}
return r;
}
public static void main(String[] args) {
System.out.println(josephus1(10000,2));
}
}


Josephus的Java实现
复杂度:$O(n)$
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: