寒假的时候看到了约瑟夫环的数学解法,感觉很厉害,不过一直没有机会再进一步的看一看它的证明,今天下午有时间了,我就阐述一下我的理解
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
约瑟夫环问题模拟是可以做的,但是运行时间太恐怖了,它的递推数学解法简单得丧心病狂,其实想来这种规律性极强的问题应该都是有递推解法的
设 一共有n人,编号1~n,每报到第m人时出列(事实上等同于编号0~n,报到第m-1个人出列),此时第k个人出列
最开始:1 2 3 4 .....n;
出列后:1 2 3 4 .... k-1 k+1 k+2...n;
将m+1号以后的数据调到1之前,然后将m+1号设置为1;
调整后 | k+1 | k+2 | k+3 | k+4 | ...... | n | 1 | 2 | 3 | ...... | k-1 |
设置后 | 1 | 2 | 3 | 4 | ..... | n-k | n-k+1 | n-k+2 | n-k+3 | ...... | n-1 |
可见一次出列前后序号的函数关系:设调整序号后的序号为X,调整前的序号为y,则有 X = y + k, 此时 k = m % n;
代入得 X = (y + m % n)% n ; // X 大于 n 时取余;
化简得 X = (y + m )% n ;
每一次出列前后的变化都如此,n人中出列 n-1 人,即调整过程循环 n-1 次,最后一个剩下的成员序号一定为 1,可逆推求得最开始的序号
化为递归式为 F[ n ] = (F[ n - 1 ] + m)% n;
之后的程序实现就很简单了。无论是递推还是直接计算,时间复杂度都是O(n)
++++++++++++++++++++++++++++++++++++++++++++
看了一下别人的博客,发现这其中还存在一个问题,当我们把 F[1] 设置为 1 时(即最后剩下的元素是1,相当于整个序列由1开始排到 n), 当 (y + m )% n = 0(如 n = 2, k = 3) 时会存在空值,因为序列中并没有0号元素,解决这个问题有两种方法:
-
设置判断条件:
因为当求得的值是0时意味着 X 被 n 整除,即 X = n;if( F[n] == 0){ F[n] = n; }
-
将序列第一个元素序号改为0,即
此时数列中的序号是 0 ~ n-1,而递推式所求值的范围也是 0 ~ n-1,正好可以相互对应F[1] = 0;