约瑟夫环的问题


/**
 * 约瑟夫环问题
 *
 *假设有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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值