/**
* 约瑟夫环问题
*
*假设有n个人、每当数到m的时候、就将第m个人出列、
*接下来从m+1个人开始从1数去、每当数到m的时候就出列
*
*===========================
第一次出列一定是编号为 (m%n - 1)剩下的人开始形成一个新的约瑟夫环
从编号为m%n开始计数 假设 k=m%n 则新的约瑟夫环为:
k k+1 k+2 k+3 ... n-2 n-1 n 0 1 2... k-2 k-1
把新的约瑟夫环的编号和第一次的约瑟夫环进行对比:
k-->0
k+1-->1
k+2-->2
k+3-->3
....
k-2-->n-2
========
k-1-->n-1 :去除的编号
========
这样从上面我们可以看出新的约瑟夫环 就是一个拥有n-1个元素的
加入我们求出了这个新的约瑟夫环的解、例如x为该n-1个环的最终胜利者
那么我们就可以推算出这个x在原来的n个元素的环中的位置
公式为:(x+k)%n %n:目的去掉整环
原来的k位置现在变成了0、相当于将原n个约瑟夫环整体向左移动了k个位置、
例如:将如下整体向左移动3个位置将3出列、超出部分补到后面
1 2 3 4 5 6 7 8 9
4 5 6 7 8 9 1 2 类似于循环队列移动
这样说来、我们如何计算n-2个约瑟夫环的解呢?同理我们只需要计算出n-3个约瑟夫环的
问题、以此类推、这样的问题就是一个递推的问题
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]
递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。
因为实际生活中编号总是从1开始,我们输出f[n]+1
由于是逐级递推,不需要保存每个f[i],程序也是非常简单:
*/
public class Yuesefu{
public static void main(String[] args) {
System.out.println(yueSeFu(500, 100));
}
public static int yueSeFu(int n,int m){
int s = 0;//表示f[1]的情况
for(int i = 2;i <= n;i++){
s = (s+m)%i;
}
return s+1;
}