您的位置:首页 > 其它

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

2014-03-11 22:06 316 查看
约瑟夫环是一个数学的应用问题:

已知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
= ( 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
;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  约瑟夫环