zoukankan      html  css  js  c++  java
  • 约瑟夫环 JosephusProblem

    问题描述:n个人 ( 编号0~(n-1) ),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。 

    最直白的方法就是用链表去模拟整个过程就好了,但是这个的复杂度有点高,算不上一个非常优秀的做法。

    下面进行推导,看是否能够推出一个通用的公式这样就可以直接得出答案:

    初始情况: 0, 1, 2 ......n-2, n-1 (共n个人)

    第一个人(编号一定是(m-1)%n,设之为(k-1) ,读者可以分m<n和m>=n的情况分别试下,就可以得出结论) 出列之后,

    剩下的n-1个人组成了一个新的约瑟夫环(以编号为k==m%n的人开始):

     k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ...,k-3, k-2 


    现在我们把他们的编号做一下转换:

    k     --> 0
    k+1   --> 1
    k+2   --> 2
    ...
    ...
    k-2   --> n-2
    k-1   --> n-1

    变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗!

    x ->x'  (这正是从n-1时的结果反过来推n个人时的编号!)

    0 -> k

    1 -> k+1

    2 -> k+2

    ...

    ...

    n-2 -> k-2

    变回去的公式 x'=(x+k)%n

    递推公式

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

    递归写法:

    int josephus(int n,int m) {
        if (n == 1)
            return 0;
        else 
            return (josephus(n-1,m) + m) % n;
    }

    迭代写法:

    int f[maxn];
    int josephus(int n,int m) {
        if (n < 1 || m < 1)
            return -1;
        for (int i = 2;i <= n;i++)
            f[i] = (f[i-1] + m) % i;
    }
  • 相关阅读:
    setTimeOut 和 setInterval对比
    vue官方源码剖析
    Taro 总结
    地图相交
    vscode 配置文件
    redis持久化的几种方式
    推荐.Net、C# 逆向反编译四大工具利器
    【转】Java 通过JDBC连接Mysql数据库的方法和实例【图文说明】
    【摘】Oracle 11g EM安全证书问题无法访问的解决办法
    MySql 从SQL文件导入
  • 原文地址:https://www.cnblogs.com/-Ackerman/p/12169034.html
Copyright © 2011-2022 走看看