您的位置:首页 > 其它

约瑟夫环问题

2016-07-11 21:48 281 查看
约瑟夫环(约瑟夫问题):已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号k的人开始报数,数到m的那个人出列;他的下一人又从1开始报数,数到m的那个人出列;依此规律重复下去,直到周围的人全部出列,最后出列人的编号是多少?(摘自百度百科)

对于这个问题,网上有很多版本的实现,包括链表、数组等,但是个人觉得实现都有点繁琐,以下是我个人的实现:

#include <iostream>

#define N 300  //总人数n
#define M 5  //报数的最大值m
#define K 1  //报数的起始编号k

/*********************************************
**本质上是利用环形双向链表解决joseph问题,不过
**此处的链表是利用数组prev
及next
实现
*************************************/

int main()
{
int prev
,next
;

for (int i=0; i<N; ++i) {
prev[i] = (i + N - 1) % N;
next[i] = (i + 1) % N;
}

int j = K - 1;
for (int k=1; j!=next[j]; j=next[j], k=(k+1)%M) {
if (k == 0) {
prev[next[j]] = prev[j];
next[prev[j]] = next[j];
}
}

std::cout << "The last number is " << j+1 << "!\n";
return 0;
}


当然,以上都属于暴力求解,算法的时间复杂度高达O(mn)。在网上对该问题的搜索,我发现有个更快捷的方法,是利用数学分析,得出问题的递归式:

f(1) = 1;

f(i) = (f(i -1) + m) % m; i > 1

注:f(i)表示i个人玩游戏报m退出最后胜利者的编号

如此,问题的时间复杂度为O(n)。

具体的推导分析可参考

http://blog.163.com/soonhuisky@126/blog/static/157591739201321341221179/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  约瑟夫环