约瑟夫环问题
约瑟夫环问题:
首先,让n个小朋友们围成一个大圈。然后,随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)。
不妨设结果为:
f(n,m).
f
(
n
,
m
)
.
先给出递推公式:
f(n,m)={[f(n−1,m)+m]%nn>1;0n=1;
f
(
n
,
m
)
=
{
[
f
(
n
−
1
,
m
)
+
m
]
%
n
n
>
1
;
0
n
=
1
;
下面推导如何得到这个递归公式:
初始序列
X
X
为:
不妨设第一次唱歌的小朋友的编号为:
k=(m−1)%n,
k
=
(
m
−
1
)
%
n
,
该小朋友出列,剩下的
n−1
n
−
1
个小朋友的序列
X′
X
′
如下:
0,⋯,k−1,k+1,⋯,n−1.
0
,
⋯
,
k
−
1
,
k
+
1
,
⋯
,
n
−
1.
由于下一个小朋友(编号为
k+1
k
+
1
)又从0开始报数,将原来编号为
k+1
k
+
1
的小朋友的编号设为0,后面的依次相加,则新的编号序列
X′′
X
″
为:
n−k−1,⋯,n−2,0,⋯,n−k−2.
n
−
k
−
1
,
⋯
,
n
−
2
,
0
,
⋯
,
n
−
k
−
2.
设初始序列
X
X
中的最后一个小盆友的编号为,序列
X′
X
′
的最后一个小朋友的编号为
f′(n,m)
f
′
(
n
,
m
)
,显然会有:
f(n,m)=f′(n,m)
f
(
n
,
m
)
=
f
′
(
n
,
m
)
。
我们将序列
X′
X
′
映射到序列
X′′
X
″
,做线性映射:
X′⟶X′′:p(x)=(x−k−1)%n.
X
′
⟶
X
″
:
p
(
x
)
=
(
x
−
k
−
1
)
%
n
.
显然逆映射为:
X′′⟶X′:p−1(x)=(x+k+1)%n.
X
″
⟶
X
′
:
p
−
1
(
x
)
=
(
x
+
k
+
1
)
%
n
.
而序列
X′′
X
″
也可以看作:
0,1,⋯,n−2.
0
,
1
,
⋯
,
n
−
2.
因此序列
X′′
X
″
的最后一个小盆友的编号为
f(n−1,m).
f
(
n
−
1
,
m
)
.
由此可以得到关系式子:
f(n,m)=f′(n,m)=p−1(f(n−1,m))=[f(n−1,m)+k+1]%n=[f(n−1,m)+m]%n.
f
(
n
,
m
)
=
f
′
(
n
,
m
)
=
p
−
1
(
f
(
n
−
1
,
m
)
)
=
[
f
(
n
−
1
,
m
)
+
k
+
1
]
%
n
=
[
f
(
n
−
1
,
m
)
+
m
]
%
n
.
推导完毕。
下面给出具体算法代码:
int JosephRing(int n, int m) {
if(n < 1 || m < 1) return -1;
int last = 0;
for(int i = 2; i <= n; ++i) {
last = (last + m) % i;
}
return last;
}