码迷,mamicode.com
首页 > 其他好文 > 详细

关于约瑟夫问题的学习

时间:2017-10-08 22:28:56      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:amp   span   优秀   表示   font   case   写法   floor   问题:   

本来我是不想学这个东西的,但是谁让他考试考到了呢?

 

约瑟夫问题:

n个人(编号为0,1,...,n-1)围成一个圈子,从0号开始依次报数,每数到第m个人,这个人就得自杀,之后从下个人开始继续报数,直到所有人都死亡为止。问最后一个死的人的编号。

 

方法1:暴力 O(nm)

 会打码的都知道。

 

方法2:白书P65 时间O(n) 空间O(1)

这是一个很容易理解的算法。

如果只关心最后一个人的编号,可以用$f(n)$表示0~n-1的n个数,从0开始每m个数删除一个,最后留下来的数字编号,那么有递推式$f(n)=(f(n-1)+m) \  mod \  n$。

怎么得来的呢?我们先用几个例子来看一看。

当n=5,m=3时:

0    1    2    3    4

死掉一个2:

0    1    3    4

相当于:

3    4    0    1

用这样排列方式的原因是我们可以发现

0    1    2    3

3    4    0    1

是可以一一对应的。

具体就是说$(0+3) \  mod \  5 = 3$、$(1+3) \  mod \  5 = 4$、$(2+3) \  mod \  5 = 0$、$(3+3) \  mod \  5 = 1$。

那么当m相同时,如果我们知道n=4的答案,就可以直接用此规律算出n=5的答案。

 

方法3:时间O(log n),空间O(log n)

仍是递推,但是并不是很复杂。

我们现在思考每轮(如果目前有n个人,0到n-1全都报一遍数叫做一轮)前后的情况。

如果n=8,m=3,则:

0    1    2    3    4    5    6    7

死掉2和5:

0    1    .     3    4     .    6    7

重新编号:

2    3    .     4    5     .    0    1

注意,我专门把死掉两个人的位置空出来,是因为这样子更直观。

我们把重新编号的序列分为两部分。一部分是2~5,一部分是0~1。

假如在重新编号后最后死的人的编号是$x$,我们需要得到的答案是$Ans$。

那么有:

$\begin{cases}& Ans =x + ( \lfloor \frac{n}{m} \rfloor \times m ) \ ,\ x \leq n \ mod \ m \\ & Ans = x - (n \  mod \ m) + ( \lfloor \frac{x-n \ mod \ m}{m-1} \rfloor ) \ ,\ x > n \  mod \ m \end{cases}$

但是注意,在$n<m$的时候,这样做就没有意义了,所以这时候只能用方法2的递推式了。

 

方法4:时间O(log n),空间O(1)

这个方法不仅可以求最后一个死的人的编号,而且可以求第k个(从0开始数)死的人的编号,而且写法贼简便,复杂度贼优秀,是当之无愧的好算法。

但是就没有前几个算法那么好懂了。

首先我们知道第$k$个自杀的人就是第$(k+1) \times m-1$次报数的人,根据他之前每次报数的时刻来确定他的编号。

例如n=5,m=3,k=5:

报数的时刻:0    1    2    3    4    5    6    7    8    9    10   11   12   13   14

人的编号:   0    1    2    3    4    0    1    3    4     1    3     1     3     3     3

我们知道第2、5、8、11、14个报数的要自杀。

我们设第$x=a \times m+b(b<m)$次自杀的人的编号为$y$。

$x$次报数后,一共死了$a=\lfloor \frac{x}{m} \rfloor$人。

如果$y$这个人没有在这次报数后自杀,那么他还需要等待剩下$n-a$人报数后才会再报数。

即他下次报数将是 $t=x+n-a=a \times m+b+n-a=a \times (m-1)+b+n$ 时刻。

那么如果我们知道这一次他报数的时刻$t$,反过来求上一次报数的时刻$x$呢?

那就是:$x=t-n+a=t-n+\lfloor \frac{t-n}{m-1} \rfloor$。

我们知道如果知道第$k$个人最后一次报数的时刻,然后反着推他上一次报数的时刻,一直到时刻数$< n$(因为是从0开始的)的时候,时刻数就是他的编号。

 

关于约瑟夫问题的学习

标签:amp   span   优秀   表示   font   case   写法   floor   问题:   

原文地址:http://www.cnblogs.com/Serene-shixinyi/p/7638510.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!