约瑟夫环数学方式求解。
我们举个例子说明一下:
n=5 即5个人的编号是0 1 2 3 4。,m=3 每3个人出队。
第一次出队的人的编号是(m-1)%n也就是 (3-1)%5=2。这很容易理解。
第一次出队后里还剩下4个人分别是0 1 3 4 。
等于我们接下来要做的就是从0 1 3 4 这4个人中,从3开始再数3个人,出队一个,以此循环,最后选出一个人来获胜。
为了推导公式:
我们可以变换一下形势:3 4 0 1,按照这个顺序从3开始计数,和上面的一样吧。(为了好理解最好自己在纸上写一下,更容易理解。)
然后不就是等价于n=4个人,0 1 2 3中从0开始计数选出一个获胜吗?(都是4个人,只是编号变了,但是位置不变)
根据位置建立对应关系对应关系:
0 -> 3 (0 + m) % 5 = 3
1 -> 4 (1 + m) % 5 = 4
2 -> 0 (2 + m) % 5 = 0
3 -> 1 (3 + m) % 5 = 1
我们假设 n个人的时候获胜的编号是 win(n) 。
那么在上面4个中肯定有一个是获胜的人有这样的关系:win(n-1) -> win(n)
其中的对应关系可以很容易的出吧。
对应关系:win(n) = ( win(n-1) + m ) % n
也就是说如果我们知道4个人的时候0 1 2 3谁获胜,然后根据对应关系就能知道5个人的时候谁获胜了吧。
这样我们就等于是把 求5个人的获胜者 转化为 求4个人的获胜者 的问题
对于4个人我们又可以转化为求3个人的问题:0 1 2 3 -->出队2,求3 0 1的问题。也就是软化为求0 1 2 的问题
对于3个人我们又可以转化为求2个人的问题:0 1 2 -->出队2,求0 1的问题,也就是转化为求0 1的问题
对于2个人我们又可以转化为求1个人的问题:0
求一个人的问题,我就不用说了吧,肯定是0呀。
然后我们来求解一下。
win(2) = ( win(1) +3 ) % 2 = 1
win(3) = ( win(2) +3 ) % 3 = 1
win(4) = ( win(3) +3 ) % 4 = 0
win(5) = ( win(4) +3 ) % 5 = 3
所以我们要想求出win(n),必须先求出win(n-1),win(n-2),…
所以有如下java的代码
public class Joseph {
public static void main(String[] args) {
int n = 5;// 编号为0 1 2 3 4
int m = 3;
// 当人数是1时,编号0获胜
int winner = 0;
for (int i = 2; i <= n; i++) {
winner = (winner + m) % i;//这里每次循环即是求win(i)获胜的编号
//等价于win(i) =(win(i-1) +m) %i;
}
System.out.println(winner);// 如果编号是从1开始 加1即可。即输出winner+1
}
}