约瑟夫问题

来源:互联网 发布:知乎金钱有术pdf 网盘 编辑:程序博客网 时间:2024/05/13 07:17

网上的解释感觉思维跳跃太大 纠结好久  现在记录一下我的代码思路

先附上搜狗百科的解释(网上都是这个版本一点创新都没有 — —!)


如果只求最后一个报数胜利者的话,我们可以用数学归纳法解决该问题,为了讨      论方便,先把问题稍微改变一下,并不影响原意:

 问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人 继续从0开始报数。求胜利者的编号。

 我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新      的约瑟夫环(以编号为k=m%n的人开始):

        k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。

现在我们把他们的编号做一下转换:

k     --> 0

k+1   --> 1

k+2   --> 2

...

...

k-2   --> n-2

k-1   --> n-1

变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解: 例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情 况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n。

令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。


下面是我的代码

int fun(int n,int m)      //n是人数 m是需要报数的个数 {        if(n==0)            return -1;        if(n==1)                         //只有一个那么在数组中的位置是0            return 0;        else            return (fun(n-1,m)+m%n)%n;    }




理解上面代码最重要的一点是:

如果知道知道去除一个倒霉蛋之后 的数组中最后胜利的人的位置     (一定会知道的 应为递归到最后数组只有一个元素)

那么他在去除一个倒霉蛋之前的数组中的位置是多少呢?

假设去除倒霉蛋之后要从k开始计数(0到m-1)

令k的起始位置为0  k+x的位置是最后胜出的人

可以很容易得出在去除倒霉蛋之前的数组里k的位置为m%n(从0开始  倒霉蛋的位置是m%n-1)

由于k+x的位置是最后胜出的人 而且 k=m%n

所以去除倒霉蛋之前的数组里x的位置是m%n+x (x在去除倒霉蛋之前的数组里总的偏移量)

m%n+x这个值可能会大于n  所以

去除倒霉蛋之前的数组里x的位置是(m%n+x)%n

我们写的函数的返回值是当前数组中胜利者的位置(从0开始)  所以

x=fun(n-1,m);       //去除一个倒霉蛋之后 的数组中最后胜利的人的位置    起始位置为0
调整一下位置就得到

(fun(n-1,m)+m%n)%n


如果读者大大发现我有写错的或有疑惑的欢迎留言讨论



1 0
原创粉丝点击