算法----约瑟夫环问题

约瑟夫环是一个数学的应用问题:

已知n个人(以编号0,1,2, … n-1 分别表示)围坐在一张圆桌周围。从编号为0的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。求最后一个出列的人的序号。。

方法 1:

模拟游戏。利用数组或者循环链表,模拟游戏的进行,直到最后仅仅留下一个数。

复杂度是 O(MN)

方法 2: O(N)

1. 一开始,n 个人: 0  1  2  3   …     m-1   m   m+1 … n-1     显然,编号 m-1 的人出列;

                                                             ||

                                                             \/

2.            新的序列:0  1  2  3 …  m-2        m   m+1 … n-1     从 编号 m 开始新的一轮游戏,

                                                              ||   因为从编号m开始,把后半段放到前面

                                                              \/         

                                 m   m+1   …  n-1       0      1      2   …   m-2

                                                              ||   编号变换 <1>, 右半部分加上 n

                                                              \/

                                 m    m+1  …   n-1      n     n+1   n+2 …  n+m-2

                                                              ||  编号变换 <2>, 全部减去 m

                                                              \/

                                 0    1   2   3  …….X ………….    n – 2

假设红色数字 X 是 [ 0 1 2 … n-2] 中最终存留的序号,我们的目标是得到这个编号经过了两次编号变换前的编号 x’。

两次编号变换的逆变换其实就是                   x’  = ( X + m) % n;

因此,我们得到了递推关系式   f [n] = ( f[n-1] + m ) % n;

f[i] —- 表示 i 个人玩这个游戏,最后存留的编号。

代码如下:

// copyright @ L.J.SHOU Mar.11, 2014
// jossef circle
#include <iostream>
#include <vector>
using namespace std;

int JosefCircle(int m, int n)
{
  vector<int> f(n+1, 0);

  for(int i=2; i<=n; ++i)
    f[i] = (f[i-1] + m) % i;

  return f[n];
}

    原文作者:约瑟夫环问题
    原文地址: https://www.cnblogs.com/shoulinjun/p/3815595.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞