约瑟夫问题的数学方法

原创 2011年03月20日 22:57:00

N个人围成一圈,顺序排号,从从第一个人开始报数,从1到3,凡报道3的退出圈子,问最后留下的第几号的那位?


/*约瑟夫问题的数学方法

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。

为了讨论方便,先把问题稍微改变一下,并不影响原意:

问题描述: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

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

令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

由于是逐级递推,不需要保存每个f[i],程序也是异常简单:*/

#include <stdio.h>
main()
{
int n, m, i, s=0;
printf("N="); scanf("%d", &n);
printf("M="); scanf("%d", &m);
for(i=2; i<=n; i++) s=(s+m)%i;
printf("The winner is %d/n", s+1);
}

/*这个算法的时间复杂度为O(n),相对于模拟算法已经有了很大的提高。算n,m等于一百万,一千万的情况不是问题了。可见,适当地运用数学策略,不仅可以让编程变得简单,而且往往会成倍地提高算法执行效率。*/

约瑟夫环问题的数学解法

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

约瑟夫问题的数学方法

 约瑟夫问题的数学方法                                      约瑟夫问题以前都是用模拟做的,速度慢得可以.刚才看到一篇好帖子,数学方法效率真不是盖的.以下转帖:无论...
  • Heluoe
  • Heluoe
  • 2008年01月26日 22:23
  • 396

约瑟夫环问题(数学方法)

问题描述: 约瑟夫环问题(Josephus) 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。写出C程序。 解法一: 思路:建立一个有N个元素的循环链...
  • dg357442101
  • dg357442101
  • 2016年02月15日 16:07
  • 233

约瑟夫环的链表解法和数学解法

约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66—70年犹太人反抗罗马的起义。约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷...
  • haishu_zheng
  • haishu_zheng
  • 2013年12月09日 11:42
  • 14180

【整理】约瑟夫问题的数学方法

【整理】约瑟夫问题的数学方法 . 2009-05-24 00:31 2074人阅读 评论(0) 收藏 举报 以前就知道约瑟夫问题是模拟,今天我才发现一些约瑟夫问题可以使用数学解法得出!真是强悍啊...
  • zwb8848happy
  • zwb8848happy
  • 2012年01月05日 21:40
  • 813

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

它的数学方法是:用推倒出递推公式f[1]=0;    f[i]=(f[i-1]+m)%i;  (i>1) 而后实现编程!#include int main(){ int n, m, i, s=0; ...
  • ahero_happy
  • ahero_happy
  • 2010年04月09日 09:43
  • 793

约瑟夫问题的N种解法

有n个囚犯站成一个圆圈,准备处决。首先从一个人开始报数,报到k的人被处死,剩下n-1个人继续这个过程,直到最终只剩下一个人留下. 问题是,给定了n和k,一开始要站在什么地方才能避免被处决?   1. ...
  • ice110956
  • ice110956
  • 2013年10月21日 16:30
  • 1523

约瑟夫环的数学方法

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们...
  • tiankonguse
  • tiankonguse
  • 2014年02月20日 14:50
  • 329

约瑟夫环问题两种情况解答

     约瑟夫环问题主要分两种,    第一种问题的描述是:N个人按顺时针围成一个圈,从1到N,然后报数,报到M的人就出去,然后剩余的人仍然围成一个圈,从出局的人下一个人开始重新报数,到M的人出局,...
  • jianzhibeihang
  • jianzhibeihang
  • 2009年12月06日 21:05
  • 5170

【c语言】使用数组解决 约瑟夫环问题

由于目前对c语言的学习仅限于数组,指针还不会用。mo'shuo
  • zyb050607
  • zyb050607
  • 2014年07月02日 13:37
  • 3142
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:约瑟夫问题的数学方法
举报原因:
原因补充:

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