约瑟夫递归的理解

看了一下午的约瑟夫问题,稍微理解了这个算法的过程:

  • 首先什么是约瑟夫问题:假如m个人围成一圈,从第一个开始报数,第n个将被杀掉,最后剩下一个,其余人都将被杀掉。例如n=5,m=6,被杀掉的顺序是:5,4,6,2,3,1。

用数组来解决这个问题显然会花费很多时间:重复多次遍历数组,经过n个人以后赋值1,标其已死亡,直到死亡人数到达m,输出最后一个人。

  • 在网上寻找了递归的办法去解决这个问题:
int ysfdg ( int sum, int value, in tn)
{
    if ( n == 1 )
        return ( sum + value - 1 ) %sum;
    else
        return ( ysfdg ( sum-1, value,n-1 ) +value ) %sum;
}

其中ysfdg表示约瑟夫递归算法,这个算法的含义是,从第一个人开始数,数到第n个人的时候,就从头开始重新数,直到只剩最后一个人。

  • 比如n=5,m=6时,将会如下:

杀人前:1 2 3 4 5 6(下面下划线表示被杀)

第一次杀人以后:1 2 3 4 _  6(此时数数为:1 2 3 4 5 6)

第二次杀人以后:1 2 3 _  _ 6(此时数数为:2 3 4 5 _ 1)

第三次杀人以后:1 2 3 _ _ _(此时数数为: 2 3 4 _ _ 1     第二遍  2 3 4 _ _ 5 )

第四次杀人以后:1 _ 3 _ _ _ (此时数数为:1 2 3 _ _ _     第二遍 4 5 6 _ _ _ )

第五次杀人以后:1 _ _ _ _ _

  • 然后用数学递归的方法表示:把每个人的编号先都减1,这样会是0~(m-1)号,方便取余运算,最后的结果需要加1还原。

第一个死掉的是编号应当是(n-1)%m号,所以说之后第二次选谁死的时候,编号 0 就是原来的编号n%m

第二个死掉的人的编号 x2 的原编号就是 ( n%m+x2 )%m = ( n+x2 )%m。编号为0是在第二次选谁死的圈中编号为 n%(m-1) 的家伙

第三个死的编号为 x3 的人在第二次的圈中编号就为 (n%(m-1)+x3)%(m-1) = (n+x3)%(m-1) ,继续推出其在最初的圈中编号为 (n+(n+x3)%(m-1))%m

知道了如何还原上一次编号的公式,但这样为什么不会出错呢?不应该剔除掉死掉的家伙吗?因为比如在第二次的圈中 x2 肯定是小于 m-1 的,加起来取余后肯定在上一个死掉的人编号前面,所以不会出现算进去已经死掉的人的问题!

按照这个思想的话,最后一个死掉的肯定是编号是0的,因为只剩他自己了,所以说这个问题就转换成了他原来的编号是多少?依次迭代即可。

迭代公式:  f ( x ) = ( f ( x-1 ) +n ) % x   ( 1<x<=m ) ,f ( 1 ) = 0
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值