`
googya
  • 浏览: 143308 次
  • 性别: Icon_minigender_1
  • 来自: 汉川
社区版块
存档分类
最新评论

【转】约瑟夫问题的数学解法

阅读更多
【转】约瑟夫问题的数学解法

写完密码约瑟夫就想到原来看到约瑟夫问题的一个数学解法   很巧妙很简单 不过只能推出最后一个出列的人

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达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>
int main()
{
  int n, m, i, s=0;
  printf ("N M = "); scanf("%d%d", &n, &m);
  for (i=2; i<=n; i++) s=(s+m)%i;
  printf ("The winner is %d\n", s+1);
  return 0;
}


这个算法的时间复杂度为O(n),相对于模拟算法已经有了很大的提高。算n,m等于一百万,一千万的情况不是问题了。可见,适当地运用数学策略,不仅可以让编程变得简单,而且往往会成倍地提高算法执行效率。
分享到:
评论
1 楼 googya 2010-11-17  
当正面不好办的时候,应该考虑一下反面。

相关推荐

    POJ 1012 约瑟夫问题的数学解法及分析

    POJ 1012 约瑟夫问题的数学解法及分析POJ 1012 约瑟夫问题的数学解法及分析POJ 1012 约瑟夫问题的数学解法及分析

    约瑟夫问题(猴子选大王)数学解法

    总的来说,约瑟夫问题的数学解法是一种结合了数论、递归和算法设计的综合性问题。它不仅在理论上有很高的研究价值,也在实际的计算机科学中有着广泛的应用,如数据结构设计、编码竞赛等。通过理解和掌握这种方法,...

    洛谷P1996约瑟夫问题多种解法及编程实现

    内容概要:本文详细介绍了洛谷P1996约瑟夫问题的各种解法,包括队列、循环链表、数组、数学方法等。每个解法都有详细的代码实现和视频讲解链接,适用于不同层次的学习者。文章还提供了丰富的背景资料,如信息学奥赛...

    约瑟夫问题面向对象解法报告书(C++版)

    ### 约瑟夫问题面向对象解法报告书(C++版)——深入解析 #### 知识点一:约瑟夫问题的经典表述与扩展 约瑟夫问题源自古罗马历史,描述了一群士兵围成一圈,按照某种规则逐个淘汰直至剩下最后一个生存者的情境。在...

    约瑟夫环最高效数学解法[O(n)]

    数学解法的关键在于观察问题的递归特性。首先,我们注意到第一个被剔除的人的编号是(M-1)%N,设这个编号为k。当这个人离开后,剩下的N-1个人形成了一个新的环,起始编号为k+1。为了简化问题,我们可以进行一次重新...

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

    约瑟夫问题的数学解决方法,可以输出淘汰的人的顺序和最后的赢家。

    约瑟夫问题代码,约瑟夫问题代码

    约瑟夫问题,又称为约瑟夫环问题(Josephus Problem),是一个著名的理论问题,源自古罗马的一个传说。问题的基本设定是:人们按照一个固定的顺序站成一个圆圈,然后从某个人开始按顺时针方向计数,每数到特定数值的...

    约瑟夫问题的由来和简介

    在约瑟夫问题的数学解法中,我们可以观察到,每次淘汰一人后,剩下的参与者形成一个新的小规模问题。通过编号转换,可以将原问题转化为一个规模较小的约瑟夫问题,然后递归地解决。这种方法避免了重复计算,显著提高...

    001.约瑟夫问题_约瑟夫问题_

    约瑟夫问题的解法不仅限于基础的编程技巧,还可以运用到图论、组合数学甚至线性代数等领域。例如,用矩阵快速幂来解决跳跃式约瑟夫问题,可以极大地提高计算效率。 此外,约瑟夫问题在实际应用中也有其价值。例如,...

    约瑟夫问题的一个题目及源代码

    约瑟夫问题,又称为约瑟夫环问题(Josephus Problem),是计算机科学与理论数学中一个著名的理论问题。该问题源于古代犹太历史学家约瑟夫·弗拉基米尔的记载,它涉及到一系列人在一个封闭的圆圈中按照特定规则进行...

    约瑟夫问题

    约瑟夫问题有多种解法,包括直接数组法、链表法、模运算法等。其中,模运算法是一种优化的解决方案,通过巧妙地使用模运算来减少循环次数,提高算法效率。这种方法的关键在于,每个人报数时其实是对一个大的循环进行...

    约瑟夫问题(猴子选王)——多种解法 1

    《约瑟夫问题(猴子选王)的多种解法详解》 约瑟夫问题,又称为猴子选王问题,是一个著名的理论问题,源自古希腊的一个传说。问题的基本设定是:一群囚犯围成一个圈,从某个人开始按顺时针方向报数,数到特定数值的人...

    约瑟夫环(Josephus Problem),又称为约瑟夫斯置换,是一个在计算机科学和数学中广泛讨论的问题 其起源于一个历史故事

    约瑟夫环约瑟夫环(Josephus Problem),又称为约瑟夫斯置换,是一个在计算机科学和数学中广泛讨论的问题。其起源于一个历史故事:在罗马人占领乔塔帕特后,约瑟夫和他的朋友与39个犹太人躲到一个洞中,他们决定以...

    yuesefu.zip_entire75w_约瑟夫算法_约瑟夫问题

    约瑟夫问题,又称约瑟夫环,是一个著名的理论问题,源自古希腊的历史传说,后由Josephus Flavius提出并被数学家们所研究。该问题涉及到了数据结构和算法设计,尤其在递归算法的应用上具有重要的教学价值。在问题中,...

    python实现约瑟夫问题

    对于约瑟夫问题,还存在一种基于数学公式的精确解法,该方法尤其适用于大规模数据处理。 约瑟夫问题的通解可以用以下公式表示: \[J(n, m) = \left\{ \begin{array}{ll} 0 & \text{if } n = 1 \\ (m + J(n - 1, m)...

    《问题解法 代数学辞典(上)》作者: (日)祾部贞市郎编 出版时间: 1982年

    作者: (日)祾部贞市郎编 出版社: 上海教育出版社 出版时间: 1982-09 版次: 一般三印 印刷时间: 1988-01 装帧: 精装 开本: 大32开 页数: 986页

    约瑟夫问题(环中有一个做杀手,即每次都跳过)

    约瑟夫问题,又称为约瑟夫环问题,是一个经典的理论问题,源于古希腊的数学家约瑟夫·弗朗西斯提出的。这个问题通常描述为:假设有一群人围成一个圆圈,从某个人开始计数,每数到特定数值的人就会被排除,然后从下一...

    acm约瑟夫问题教程

    文档《约瑟夫环问题.doc》和《约瑟夫问题.doc》可能包含对问题的深入分析、各种解法的详细解释、实例演示以及一些特殊情况的讨论,对于学习和理解约瑟夫问题非常有帮助。通过阅读这些文档,你可以更深入地了解这个...

    达朗贝尔解法解决数学物理方程

    总之,达朗贝尔解法是一种强大的工具,用于解决数学物理中的波动问题,特别是对于一维波动方程。通过对二阶线性偏微分方程分类,并利用行波解法,我们可以根据方程的类型找到适当的解。对于一维波动方程,达朗贝尔...

    约瑟夫问题详解(C_C++)

    这些问题通常在基本的约瑟夫问题框架上增加了额外的条件或限制,如特定的报数规则、二进制转换、字符操作等,但核心的解决思路仍然依赖于递归或数学变换的策略。 例如,在处理一半好人一半坏人的问题时,通过模拟或...

Global site tag (gtag.js) - Google Analytics