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

原创 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;
}


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

约瑟夫环(数学高效率解法,很详细)

 5.5.4 用数学方法解约瑟夫环(1) 原文copy:http://book.51cto.com/art/201403/433941.htm 5.5.4  用数学方法解约瑟夫环(1...
  • qq_25973267
  • qq_25973267
  • 2015年12月25日 22:49
  • 4875

约瑟夫环问题的数学解法

问题描述:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围...
  • allenhappy
  • allenhappy
  • 2014年05月23日 17:30
  • 1446

约瑟夫环的数学推导、数学方法求最后出圈的数字、循环单链表求所有出圈数字顺序

约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围;从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下...
  • wwj_ff
  • wwj_ff
  • 2015年06月23日 18:45
  • 833

约瑟夫环问题及其尽可能的优化

约瑟夫问题描述: n个人围成一个圈,编号为0,1,2,..,n-1,设定一个常数k,然后从0号开始从1依次报数,报到k的那个人退出圈,后面一个人继续从1开始报数,依次类推,求最后剩下的人的编号 方...
  • yingzinanfei
  • yingzinanfei
  • 2016年04月17日 18:47
  • 1018

详细阐述约瑟夫环问题(报数出队问题)

约瑟夫环问题(Josephus)       用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。(约瑟夫环问题 Josephus) 直接上代...
  • Double2hao
  • Double2hao
  • 2015年10月05日 16:51
  • 1700

约瑟夫环问题的公式推导

题目:有n个人围成一个圈,将他们编号1~n从第k个人开始报数,每次报到m的人退出,问:最后留下的那个人编号为多少。...
  • zjzytnn
  • zjzytnn
  • 2015年07月16日 23:42
  • 261

约瑟夫环-两种实现方法,两种时间复杂度

已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为r的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出...
  • zzran
  • zzran
  • 2012年11月24日 16:32
  • 3336

10行Python代码解决约瑟夫环(模拟)

写这篇文章是因为看到别人博客里用了很长一个篇幅(超过50行)去解决一个约瑟夫环问题,而且还是用以简洁著称的python,另外,如果你用X度搜索python 约瑟夫,看到得前几条都是错的,真是好悲剧。 ...
  • u011044759
  • u011044759
  • 2014年09月11日 17:21
  • 30621

约瑟夫环(约瑟夫问题的变形,LA 3882)

只是问最后剩下的是哪个,而没有问具体是怎么删除的,所以不需要完全模拟,只需要模拟编号就好了。 一开始有n个,分别编号为   0,1,2,3,...n-1。 删除第k个,即编号为k-1的那个...
  • xl2015190026
  • xl2015190026
  • 2016年10月27日 23:51
  • 373

Java实现约瑟夫环问题

约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;...
  • qq_21150865
  • qq_21150865
  • 2017年03月05日 14:48
  • 4505
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:约瑟夫环问题数学优化方法
举报原因:
原因补充:

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