约瑟夫问题(Josephus Problem)的两种快速递归算法
- 博文链接:http://haoyuanliu.github.io/2016/04/18/Josephus/
- 对,我是来骗访问量的!O(∩_∩)O~~
约瑟夫问题(Josephus Problem)也称“丢手绢问题”,是一道非常经典的算法问题,其解法涉及了链表、递归等算法和数据结构,本文主要分为如下三个内容:
- 使用C语言定义循环链表,通过遍历链表模拟事件处理过程;
- 使用数学方法,找出第
n - 1步与第n步的关系,通过递归解决问题;- 对第二种方法进行优化,加速递归过程,提高算法效率
循环链表(C语言)
代码
#include <stdio.h>
#include <stdlib.h>
//定义循环链表
typedef struct node//定义node结构体
{
int data;
struct node* next;
}cLinkList;//typedef struct node* cLinkList;定义一个struct node类型的循环链表
//主函数
int main()
{
cLinkList *head, *p, *s, *temp;
int n, k;
int i = 1;
printf("Please enter the total number n:\n");
scanf("%d", &n);
printf("Please enter the key value:\n");
scanf("%d", &k);
k %= n;
head = (cLinkList *)malloc(sizeof(cLinkList));
p = head;
p->next = p;//这里要赋值为p,不能赋值为head,要保持head的位置不变
p->data = i;
for(i = 2; i <= n; i++)
{
s = (cLinkList *)malloc(sizeof(cLinkList));
s->data = i;
s->next = p->next;
p->next = s;
p = s;
}
p = head;
int total = n;
while(n--)
{
for(i = 1; i < k - 1; i++)
{
p = p->next;
}
printf("%d->", p->next->data);
temp = p->next;//temp为要删除的元素
p->next = temp->next;//链表中跳过temp
free(temp);//释放temp
p = p->next;//p向前移动继续寻找
}
printf("Done!\n");
return 0;
}
运行过程如下:

程序分析
这段代码主要使用了循环链表的数据特性和结构特性,非常适合用来进行Josephus问题的模拟,但是相对来说处理问题的复杂度较高,下面将介绍两种更加高效的算法。
第一种递归
原理
令f[n]表示当有n个候选人时,最后当选者的编号。则:
f[1] = 0
f[n] = (f[n - 1] + K) mod n
方法证明
上述公式可以用数据归纳法简单证明其正确性:
f[1] = 0
当只有一个候选人的时候,显然结果应该是0
f[n] = (f[n - 1] + K) mod n
f[n - 1]为第n - 1次数到的id序列,则第n次就是再往下数k个,最后进行取模运算即可得到结果序列
这种算法的时间复杂度为O(N),空间复杂度为O(1),效率有所提高!
代码
#include <iostream>
using namespace std;
int main()
{
int num, n, k;
cin >> num;
while(num--)
{
int ret = 0;
cin >> n >> k;
for(int i = 2; i <= n; ++i)
{
ret = (ret + k) % i;//ret记录每一次数到的序列号
}
cout << ret << endl;//输出最终序列结果
}
return 0;
}
第二种递归
原理
- 在每一轮报数过程中,都有
N/K个人退出了队伍,比如N = 10, K = 3,第一轮有N / K = 3三个人退出;- 上述第一种方法每次递归的步长为
1,这里我们利用上述关系,建立一个步长为N / K的递归过程;- 需要注意的是,当
N减少到N = K的时候就需要使用第一种递归进行计算;N > K时的递归公式为:
ret < N mod K: ret = ret - (N mod K) + N
ret >= N mod K: ret = ret - (N mod K) + (ret - N mod K) / (K - 1)
代码
#include <iostream>
using namespace std;
int josephus(int n, int k)
{
int ret;
if(n == 1)
return 0;
//n < k的时候使用第一种递归算法
if(n < k)
{
int ret = 0;
for(int i = 2; i <= n; ++i)
ret = (ret + k) % i;
return ret;
}
//执行递归过程
ret = josephus(n-n/k,k);
if(ret < n % k)
{
ret = ret - n % k + n;
}
else
{
ret = ret - n % k + (ret - n % k ) / (k - 1);
}
return ret;
}
int main()
{
int num;
cin >> num;
while(num--)
{
int n, k;
cin >> n >> k;
cout << josephus(n, k) << endl;
}
return 0;
}
代码分析
这个算法加快了递归算法的迭代速度,当所求N比较大K比较小的时候比较适用,能够以更快的速度进行求解。
Github: https://github.com/haoyuanliu
个人博客: http://haoyuanliu.github.io/
个人站点,欢迎访问,欢迎评论!
约瑟夫问题(Josephus Problem)的两种快速递归算法的更多相关文章
- 算法Sedgewick第四版-第1章基础-017一约瑟夫问题(Josephus Problem)
/************************************************************************* * * Josephus problem * * ...
- 文件批量上传-统一附件管理器-在线预览文件(有互联网和没有两种)--SNF快速开发平台3.0
实际上在SNF里使用附件管理是非常简单的事情,一句代码就可以搞定.但我也要在这里记录一下统一附件管理器能满足的需求. 通用的附件管理,不要重复开发,调用尽量简洁. 批量文件上传,并对每个文件大小限制, ...
- Android 利用an框架快速实现夜间模式的两种套路
作者:Bgwan链接:https://zhuanlan.zhihu.com/p/22520818来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 网上看到过大多实现夜间模 ...
- 使用Idea当中的快捷键快速查看继承关系或其图表的两种方法
一.Idea当中有两种方法可以查看继承关系 在Idea当中选中一个类,然后按Ctrl+H,可以快速查看当前所选类的继承关系,如下图: 同样选中一个类,按CTRL+ALT+U,即可生成当前类的继承关 ...
- iOS同一项目多个Target的快速实现方法 - 两种使用场景详解
我们项目中,默认建好是只有一个target的,但是,一些场景中,多target能帮助我们更好的使用项目. 场景1: 同一项目,一般会分不同环境:开发环境.测试环境.正式(生产)环境. 这就涉及到一个请 ...
- 消息队列:快速上手ActiveMQ消息队列的JMS方式使用(两种模式:Topic和Queue的消息推送和订阅)
1.实现功能 希望使用一套API,实现两种模式下的消息发送和接收功能,方便业务程序调用 1.发送Topic 2.发送Queue 3.接收Topic 4.接收Queue 2.接口设计 根据功能设计公共调 ...
- 快速掌握RabbitMQ(四)——两种消费模式和QOS的C#实现
本篇介绍一下RabbitMQ中的消费模式,在前边的所有栗子中我们采用的消费者都是EventingBasicConsumer,其实RabbitMQ中还有其他两种消费模式:BasicGet和QueueBa ...
- 排产的两种方式(前推式与后拉式)在Optaplanner上的体现
生产计划的约束 在制定生产计划过程中,必然是存在某些制约因素,满足某些需求才能进行的,或是交期保证.或是产能限制.或是关键工序制约.即TOC理论 - 任何系统至少存在着一个制约因素/瓶颈:否则它就可能 ...
- Josephus Problem的详细算法及其Python、Java实现
笔者昨天看电视,偶尔看到一集讲述古罗马人与犹太人的战争--马萨达战争,深为震撼,有兴趣的同学可以移步:http://finance.ifeng.com/a/20170627/15491157_0. ...
随机推荐
- ajax跨域传值
<script type="text/javascript"> function xmlpage(){ $.ajax({ url:'http://localhost/3 ...
- CSS3美化表单控件
表单的默认控件在不同的浏览器中的样式不同,用户体验很差.用CSS3可以实现表单控件的美化,可以提供更好的用户体验.不足之处就是浏览器的兼容性问题. 一.下拉控件 效果图: 下拉控件的布局结构: < ...
- SGU 224.Little Queens
时间限制:0.75s 空间限制:6M 题意 n*n(n<=10)的棋盘,求出放置m(m<=n*n)个皇后的方案数. Solution: 状态压缩+位运算 搜索. 首先我们从上往下逐行放置 ...
- 【cogs858】磁性链
[题目描述] 有N块编号为1~N的特殊磁石相互吸附组成一条磁性链,只有它们紧挨着时才会传递吸力,他们之间的吸力很大,如果我们要从N块相连的磁石中取出一块,那么需要消耗N-1个单位的能量,空缺处不再有吸 ...
- TatukGIS-TGIS_ShapeArc.GetPointOnLine
function GetPointOnLine(const _distance: Double; const _offset: Double; const _part: Integer): TGIS_ ...
- SSH三种框架及表示层、业务层和持久层的理解
Struts(表示层)+Spring(业务层)+Hibernate(持久层) SSH:Struts(表示层)+Spring(业务层)+Hibernate(持久层) Struts:Struts是一个表示 ...
- 欧拉计划(1~3)ps:以后看题一定要认真
那天的题挺简单的 下面来看下 No1 If we list all the natural numbers below 10 that are multiples of 3 or 5, we get ...
- 子类化窗口控件的窗口过程(系统级替换,与直接替换控件的WndProc方法不是一回事)
要说灵活性,自然是比不上Delphi自带的覆盖WndProc,或者替换WndProc方法. unit Unit1; interface uses Windows, Messages, SysUtils ...
- android:TextAppearance.Material.Widget.Button.Inverse找不到或者报错问题
前两天将android sdk升到android6.0后出现Error retrieving parent for Item - AppCompact-v7 23 或者无法解析 android:Tex ...
- [置顶] 2014年八大最热门IT技能
根据Computerworld网站组织的年度预测调查,众多IT专业人士在2014年所面临的整体就业形势与今年基本持平——今年有33%的企业有计划增加IT部门的员工数量,而未来一年则有32%的企业有此打 ...