约瑟夫问题
Posted yuanquming
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了约瑟夫问题相关的知识,希望对你有一定的参考价值。
全都是抄具体数学的
问题(1)
有(n)个人围成一圈,顺时针从(1)到(n)编号,并从(1)开始报数,如果一个人报的数字是(2)的倍数,就把他撒了,后面的人继续,问最终活下来的人的编号
(Sol1)
记(J(n))为最终活下来人的编号,有(J(1)=1)
如果有(2n)个人,那么第一圈过去之后所有偶数编号的人都被撒了,那么可以看成还有(n)个人,只不过第(i)个人的编号是(2i-1),所以有(J(2n)=2J(n)-1)
如果有(2n+1)个人,那么第一圈过去之后所有偶数编号的人都被撒了,下一圈一开始(1)号被撒了,那么可以看成还有(n)个人,第(i)个人的编号是(2i+1),所以有(J(2n)=2J(n)+1)
如果我们记(k)为(n)的二进制最高位,有(J(n)=2(n-2^k)+1)打表证明即可,归纳证明即可
问题(2)
有(n)个人围成一圈,顺时针从(1)到(n)编号,并从(1)开始报数,如果一个人报的数字是(3)的倍数,就把他撒了,后面的人继续,问最终活下来的人的编号
(Sol2)
如果还是按上面的递归式的方法不用做了
考虑一种新的方法,(1)号报完之后,我们给他一个新的编号(n+1),(2)号报完之后变成(n+2),(3)号报完就被撒了,(4)号报完变成(n+3)……同理,每一次令(3k+1)和(3k+2)的人变成(n+2k+1)和(n+2k+2)
这样的话第(k)个死的人编号是(3k),最终活下来的人编号就是(3n)了,我们只要知道他原来的编号就行了
对于编号为(p)的人,如果(p>n),那么(p=n+2k+v),其中(v=1)或(2),所以有(k=lfloor{p-n-1over 2} floor),而它之前的号码是(3k+v),即(3k+(p-n-2k)=p+k-n),那么我们可以写出一个代码
inline int calc(R int n){
R int p=3*n;
while(p>n)p=((p-n-1)>>1)+p-n;
return p;
}
关于复杂度的证明,它和下面这种方法等价
如果我们记(d=3n+1-p),那么递归过程就变成了
[ egin{aligned} d &=3n+1-left(lfloor{{3n+1-d-n-1}over 2} floor+3n+1-d-n ight)&=n+d-lfloor{2n-dover 2} floor&=d-lfloor{-dover 2} floor&=d+lceil{dover 2} ceil&=lceil{3dover 2} ceil\end{aligned} ]
代码如下
inline int calc(R int n){
R int d=1;
while(d<=(n<<1))d=ceil(1.5*d);
return 3*n+1-d;
}
由于这两种方法本质一样,所以复杂度都是(O(log n))
问题(3)
有(n)个人围成一圈,顺时针从(1)到(n)编号,并从(1)开始报数,如果一个人报的数字是(q)的倍数,就把他撒了,后面的人继续,问最终活下来的人的编号
(Sol3)
在问题(2)的基础上扩展一下即可
inline int calc(R int n,R int q){
R int d=1;
while(d<=(q-1)*n)d=ceil(1.0*q/(q-1)*d);
return q*n+1-d;
}
参考资料
《具体数学》
以上是关于约瑟夫问题的主要内容,如果未能解决你的问题,请参考以下文章