约瑟夫环问题数学优化方法

原创 2017年02月26日 19:52:59

约瑟夫环问题来历:


   据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。[1] 
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。


数学优化方法如下:


        为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。


      我们知道第一个人(编号一定是(m-1)%n) 出列之后,剩下的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


     n-1 –> n-1-k     0–> n-k


        … …   


     k-3 –> n-3   k-2 –> n-2


     序列1: 1, 2, 3, 4, …, n-2, n-1, n


     序列2: 1, 2, 3, 4, … k-1, k+1, …, n-2, n-1, n


     序列3: k+1, k+2, k+3, …, n-2, n-1, n, 1, 2, 3,…, k-2, k-1   


     序列4:1, 2, 3, 4, …, 5, 6, 7, 8, …, n-2, n-1   


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


    ∵ k=m%n;   


       ∴ x’ = x+k = x+ m%n ; 而 x+ m%n 可能大于n


       ∴x’= (x+ m%n)%n = (x+m)%n   得到 x‘=(x+m)%n


        如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 —- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:


      令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n].


      递推公式:   f[1]=0;   f[i]=(f[i-1]+m)%i; (i>1)

代码实现

#include<cstdio>
int main()
{
    int n,m,ans;   //n为人数,m为数到m的人自杀
    while(~scanf("%d%d",&n,&m))
    {
        ans=0;
        for(int i=2;i<=n;i++)
            ans=(ans+m)%i;   //递推
        printf("%d\n",ans+1);  //由于假设编号从0开始所以最后答案应该加1
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

约瑟夫环的数学优化方法

首先,约瑟夫环的数学优化方法为:         为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报...

约瑟夫问题(优化优化再优化)

1 什么是约瑟夫问题 约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那...

给一个正整数 n, 找到若干个完全平方数(比如1, 4, 9, ... )使得他们的和等于 n。你需要让平方数的个数最少。

给出 n = 12, 返回 3 因为 12 = 4 + 4+ 4。 给出 n = 13, 返回 2 因为 13 = 4 + 9。 /* *思路: *1设置n的副本为t *2.先求出平方数小于t的最...

C++ 高精度算法及N的阶乘

高精度算法

Josephus(约瑟夫)环问题的数学方法,使用递推公式。

Josephus(约瑟夫)环问题的数学方法,使用递推公式。

约瑟夫问题的数学解决方法

  • 2013年03月27日 21:11
  • 363B
  • 下载

约瑟夫问题的数学方法

N个人围成一圈,顺序排号,从从第一个人开始报数,从1到3,凡报道3的退出圈子,问最后留下的第几号的那位?/*约瑟夫问题的数学方法无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程...
  • shh110
  • shh110
  • 2011年03月20日 22:57
  • 183

UVa 3882 And Then There Was One(stl+有技巧的模拟||数学方法+约瑟夫问题)

Let’s play a stone removing game. Initially, n stones are arranged on a circle and numbered 1, …, n ...

百练-2746-OpenJudge(约瑟夫问题分析二,数学方法)

#include #include int main() {    int n, m, i,s;    while(scanf("%d%d",&n,&m)&&(n||m))    {  ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:约瑟夫环问题数学优化方法
举报原因:
原因补充:

(最多只允许输入30个字)