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

约瑟夫环非递归算法和递归算法分析与实现(ZZ)

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


【求解思路】
1.非递归算法
我们知道第一个人(编号一定是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],程序也是异常简单:
int main()
{
    int n, m, i, s=0;
    scanf("%d%d", &n, &m);
    for (i=2; i <=n; i++)
        s=(s+m)%i;
    printf ("The winner is %d/n", s+1);
}


2.递归算法

当n个人时,退出的一定是报到m%n-1的人(有%是因为m可能大于n,经过循环才能报到m),由于所有人是一个环,可以认为是从任何地方开始编号的,所以在m%n-1这个人之后的人可以认为编码都大于他,那么整个环的编号就是m%n-1到m%n-1+n-1(也就是m%n-1到m%n-2,实际上一个编号是m还是m+n或者m+2n都无所谓,只要最终算出来的编号对n取模就是正确的编号了。)
那此人退出后他的下一位,也就是原来报m%n这位的编号将更新为0。相应的后面的编码都会减少m%n,所以得出公式:
f[n] - m%n = f[n-1]
变形一下公式也就是:
f[n] = (f[n-1] + m) % n
由此公式得到递归算法(注,要是跟非递归保持一致的话,可以将最后返回值+1)
int f(int n, int m)
{
    if (n > 1)
        return (m + f(n - 1, m)) % n;
    else
        return 0;
}

分享到:
评论

相关推荐

    快速排序算法设计与分析总结 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现

    快速排序算法设计与分析总结 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现 二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现,应包含建树的实现 实现树与...

    VC对磁盘文件遍历搜索的递归算法和非递归算法

    在VC++(Visual C++)环境中,有多种方法可以实现这一目标,其中最常见的是递归算法和非递归算法。这两种方法各有优缺点,适用于不同的场景。 **递归算法**: 递归算法是一种基于函数自身调用解决问题的方法。在...

    5!递归算法和非递归算法

    为了更好地理解递归与非递归算法的区别,我们可以通过计算阶乘的例子来具体分析: #### 递归算法示例 ```java public class DiGui { public static void main(String[] args) { System.out.println(f(5)); } ...

    快速选择非递归与递归算法实现

    以上就是关于快速选择算法的非递归和递归实现的详细介绍。通过合理地选取基准和适当的数据结构,快速选择算法可以在大数据集上提供高效的k-th最小元素查找服务。在Java中的`QuickSelect.java`文件中,应该包含了这些...

    汉诺塔问题的非递归算法

    它不仅是算法设计与分析中的一个经典案例,而且是计算机编程中的一个重要示例。汉诺塔问题通常由三根柱子和若干大小不一的圆盘组成,通过一系列的移动规则,将所有的圆盘从起始柱子移动到目标柱子,这个过程需要遵循...

    合并排序递归和非递归算法

    3. **可读性和实现难度**:递归算法通常代码简洁,易于理解,而非递归算法可能需要更复杂的逻辑来模拟递归行为。 总的来说,选择哪种实现方式取决于具体场景,如内存限制、性能要求以及代码的可读性等。递归版本的...

    数据结构DFS深度优先遍历非递归算法实现

    数据结构DFS深度优先遍历非递归算法实现,是自己编写的,可靠。

    二叉树遍历的非递归算法分析与实现

    ### 二叉树遍历的非递归算法分析与实现 #### 一、引言 在数据结构领域中,二叉树作为一种基本的数据组织形式,其应用极为广泛。对于二叉树的操作,其中最重要的就是遍历操作。遍历是指按照特定顺序访问二叉树的...

    约瑟夫(非递归方法).算法

    关于约瑟夫(非递归方法).算法算法的代码,自己写的,和大家分享,希望大家能多多指教

    Hanoi塔问题的一种非递归算法

    不同于传统意义上的二叉树应用,该算法巧妙地利用满二叉树的概念来组织和分析Hanoi塔问题的解,从而设计出一种高效、易于理解和实现的非递归方案。 #### 四、非递归算法的设计思路 在深入分析Hanoi塔问题递归解的...

    先序遍历的非递归算法

    "先序遍历的非递归算法" 本文将详细介绍二叉树的先序遍历非递归算法,包括其原理、实现代码和相关知识点。 知识点1:二叉树的概念 ...通过学习本文,读者可以更好地理解树遍历算法和非递归算法的原理和实现。

    中序遍历二叉树非递归算法

    在IT领域,尤其是在数据结构与算法的学习中,中序遍历二叉树的非递归算法是一个关键且实用的知识点。通常,我们首先通过递归来实现二叉树的遍历,但递归方法可能因深度过大导致栈溢出,因此掌握非递归版本的遍历算法...

    二叉树先序、中序、后序三种遍历的非递归算法

    二叉树三种遍历非递归算法 二叉树是一种常用的数据结构...这三种遍历方法的非递归算法都使用栈来实现遍历,每种算法的实现代码都有其特点和优点。但是,无论是哪种遍历方法,都是对二叉树中的每个结点进行访问的过程。

    阿克曼函数 c程序 递归与非递归算法的综合

    通过比较这两个程序,你可以看到递归和非递归算法在实现上的差异,以及它们在处理复杂递归问题时的不同策略。 理解并分析这两个程序,可以帮助你深入学习C语言编程,特别是递归和栈的概念。同时,这也为理解递归...

    汉诺塔递归与非递归两种算法的代码与结果对比

    "非递归解决汉诺塔,每一步都有确切解.doc"文件很可能提供了非递归算法的详细步骤和解释,每一步都确保了盘子的合法移动,确保最终能将所有盘子从A移动到C。 **结果对比** "no differences"的结果表明,无论使用...

    递归算法与非递归转化

    递归算法与非递归转化 递归算法是把问题转化为规模缩小了的同类问题的子问题...递归算法易于理解和实现,但效率较低;非递归算法效率较高,但实现起来较为困难。因此,在选择算法时,需要根据具体情况进行选择和权衡。

    二叉树与树的转换前序、后序的递归、非递归算法,层次序的非递归算法的实现,应包含建树的实现。

    根据给定文件的信息,本文将详细介绍二叉树与树之间的转换方法,并且深入探讨树的前序、中序、后序遍历递归与非递归实现方式,以及层次遍历的非递归算法实现。 ### 二叉树与树的转换 在计算机科学中,树是一种常用...

    8皇后算法的非递归算法

    用非递归解决八皇后的问题,是经典的非递归算法,学习数据结构中很有用

    二叉树先序遍历、中序遍历和后序遍历非递归算法 C++源码

    用C++写的二叉树先序遍历、中序遍历和后序遍历非递归算法

    数据结构 二叉树三种遍历的非递归算法(背诵版).doc

    本篇文章将深入探讨二叉树三种主要遍历方式(前序、中序、后序)的非递归算法实现,力求让读者能够清晰地理解和掌握这些算法,并在实践中加以应用。 **前序遍历**是二叉树遍历的一种基本形式,其遍历顺序是先访问根...

Global site tag (gtag.js) - Google Analytics