zoukankan      html  css  js  c++  java
  • 约瑟夫环问题,一道经典的数据结构题目

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

    一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方式求解,需要大量的时间来模拟退出的过程,而且由于需要占用大量的内存空间来模拟队列中的n个人,并不是一个很好的解法。

    在大部分情况下,我们仅仅需要知道最后那个人的编号,而不是要来模拟一个这样的过程,在这种情况下,可以考虑是否存在着一种数学公式能够直接求出最后那个人的编号。

    我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):

    我们先看第一个人出列后的情况,显而易见,第一个出列的人的编号一定是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-1

    可以看出,这就是原问题中把n替换成n-1的情况,假设我们已经求出来在这种情况下(即n-1个数字时)最后胜利的那个人的编号是n-1中的x,那个倒推回去的n个数字时那个人的编号就是我们要求的答案,显而易见,这个编号应该是(x+k)%n,而k=m%n,所以这个编号为(x+m)%n.

    那么如何知道n-1个人下面的这个x呢,yes,就是n-2个人情况下得到的x’倒推回去,那么如何知道n-2情况下的x’呢,当然是求n-3个人,这就是一个递归的过程

    f(1) = 0(f(1)就是现在还剩下1个人,那么无论m为几,这个人总会出列,因此f(1)=0)

    f(n) = (f(n-1)+m)%n

    那么我们要求f(n),就从f(1)倒推回去即可。

    #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 ”, s+1);

    }

    转载请注明:约瑟夫环问题,一道经典的数据结构题目

  • 相关阅读:
    自此KYang独一人
    根本不存在 DIV + CSS 布局这回事转
    释德扬,少林大师教你简易健身法
    只让指定的机器连接SQLServer服务器
    Visual Studio 2005 IDE模板丢失的解决方法
    asp.net 未能加载视图状态
    如何控制触发器递归
    4G相关标准UMB/LTE/WiMAX介绍
    Linq To Sql 项目从Beta迁移到RTM注意事项
    保护眼睛的windows窗口颜色
  • 原文地址:https://www.cnblogs.com/whiterock/p/8158812.html
Copyright © 2011-2022 走看看