约瑟夫环的问题

假定一共有n个人围成一圈,随机从某个人开始报数,从0报数,第m个报数的人(报数为m-1)从圈中删除。那么最后剩下的人的在第一轮中报数是多少(即,开始时候的编号是多少?)

假定这里剩下的人是JACK,令函数f (n,m)表示jack在首轮n个人中的编号
第一轮n个人理论上报数顺序应该是 0    1    2    。。。    n-1(只不过报到M-1之后,后面的人不用继续报出来,但是编号还是存在的)
删除一个人,这个人假设编号为K    其实这个K是可以求出的    即:K =(M-1)%N ;
所以剩下的n-1个人 是  0    1    2    K-1    k+1    。。。    n-2    n-1 
第二轮开始,要从第一轮中编号为    K+1 的那个人开始报数,报数的顺序在第一轮中对应的报数为
Num1:       K+1    K+2    ...    N-1    0    1    2   .... K-1   
但是他们报数喊出的数还是要从0开始  ,也就是说第二轮开始对他们进行重新编号,编号为m-1的人要出列。
Num2:        0            1         N-K-2                         N-2

所以如果知道第二轮Jack的编号为x的话,是可以反推出Jack在第一轮中的编号的。
即    Num2(x') ---》 Num1(x)的转换为:
            0                K+1
            1                  k+2
            。。。。。。。
            N-2               K-1
总结规律是:用x表示上一轮的编号,x'表示这一轮的编号
那么        x = (x' +k+1)%n = (x'+ (m-1)%n  +1 )%n = (x' + m) %n

所以对于Jack有上一轮他的编号与本轮编号之间的关系:    f (n.m) = (f (n-1,m)+m)%n
那么最后剩下Jack一个人时,他的编号肯定是0所以有
 
f(n,m) = 0 ;n=1
f(n,m) = (f (n-1,m)+m)%n;  n>1
那么利用迭代递推就可以从一开始确定第一次报数的人当中报数为几的人最终回留下来,编码实现就很简单了
public int Recusion(int n,int m){
    	if(n<1|m<1){return -1;}
    	int f = 0;
    	for(int i=2;i<=n;i++){
    		f =(f+m)%i;
    	}
    	return f;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值