• Josephus Problem


    问题描述:
    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$

    代码实现:

     1 public class Josephus {
     2     public static int josephus0(int n,int k){
     3         int r = 0;
     4         for(int i=2;i<=n;i++){
     5             r = (r + k) % i;
     6         }
     7         return r;
     8     }
     9     public static int josephus1(int n,int k){
    10         int r = 1;
    11         for(int i=2;i<=n;i++){
    12             r = (r + k - 1) % i + 1;
    13         }
    14         return r;
    15     }
    16     public static void main(String[] args) {
    17         System.out.println(josephus1(10000,2));
    18     }
    19 }
    Josephus的Java实现

    复杂度:$O(n)$

    作者:xiazdong
    出处:http://blog.xiazdong.info
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。
  • 相关阅读:
    20155239 2016-2017-2 《Java程序设计》第5周学习总结
    学习Java的必要知识点记录
    # 20155226 2016-2017-2 《Java程序设计》第4周学习总结
    随笔三 第三周学习
    第二周学习
    吕宇轩20155239 第一周
    随笔三 安装Linux操作系统
    随笔二
    随笔一
    java动态代理(JDK和cglib)
  • 原文地址:https://www.cnblogs.com/xiazdong/p/3104117.html
Copyright © 2020-2023  润新知