约瑟夫问题(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比较小的时候比较适用,能够以更快的速度进行求解。



Githubhttps://github.com/haoyuanliu

个人博客http://haoyuanliu.github.io/

个人站点,欢迎访问,欢迎评论!

约瑟夫问题(Josephus Problem)的两种快速递归算法的更多相关文章

  1. 算法Sedgewick第四版-第1章基础-017一约瑟夫问题(Josephus Problem)

    /************************************************************************* * * Josephus problem * * ...

  2. 文件批量上传-统一附件管理器-在线预览文件(有互联网和没有两种)--SNF快速开发平台3.0

    实际上在SNF里使用附件管理是非常简单的事情,一句代码就可以搞定.但我也要在这里记录一下统一附件管理器能满足的需求. 通用的附件管理,不要重复开发,调用尽量简洁. 批量文件上传,并对每个文件大小限制, ...

  3. Android 利用an框架快速实现夜间模式的两种套路

    作者:Bgwan链接:https://zhuanlan.zhihu.com/p/22520818来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 网上看到过大多实现夜间模 ...

  4. 使用Idea当中的快捷键快速查看继承关系或其图表的两种方法

    一.Idea当中有两种方法可以查看继承关系 在Idea当中选中一个类,然后按Ctrl+H,可以快速查看当前所选类的继承关系,如下图: ​ 同样选中一个类,按CTRL+ALT+U,即可生成当前类的继承关 ...

  5. iOS同一项目多个Target的快速实现方法 - 两种使用场景详解

    我们项目中,默认建好是只有一个target的,但是,一些场景中,多target能帮助我们更好的使用项目. 场景1: 同一项目,一般会分不同环境:开发环境.测试环境.正式(生产)环境. 这就涉及到一个请 ...

  6. 消息队列:快速上手ActiveMQ消息队列的JMS方式使用(两种模式:Topic和Queue的消息推送和订阅)

    1.实现功能 希望使用一套API,实现两种模式下的消息发送和接收功能,方便业务程序调用 1.发送Topic 2.发送Queue 3.接收Topic 4.接收Queue 2.接口设计 根据功能设计公共调 ...

  7. 快速掌握RabbitMQ(四)——两种消费模式和QOS的C#实现

    本篇介绍一下RabbitMQ中的消费模式,在前边的所有栗子中我们采用的消费者都是EventingBasicConsumer,其实RabbitMQ中还有其他两种消费模式:BasicGet和QueueBa ...

  8. 排产的两种方式(前推式与后拉式)在Optaplanner上的体现

    生产计划的约束 在制定生产计划过程中,必然是存在某些制约因素,满足某些需求才能进行的,或是交期保证.或是产能限制.或是关键工序制约.即TOC理论 - 任何系统至少存在着一个制约因素/瓶颈:否则它就可能 ...

  9. Josephus Problem的详细算法及其Python、Java实现

      笔者昨天看电视,偶尔看到一集讲述古罗马人与犹太人的战争--马萨达战争,深为震撼,有兴趣的同学可以移步:http://finance.ifeng.com/a/20170627/15491157_0. ...

随机推荐

  1. 主成份分析PCA

    Data Mining 主成分分析PCA 降维的必要性 1.多重共线性--预测变量之间相互关联.多重共线性会导致解空间的不稳定,从而可能导致结果的不连贯. 2.高维空间本身具有稀疏性.一维正态分布有6 ...

  2. clipboard.js IE下 不允许复制时, 问题修改

    问题描述:https://github.com/zenorocha/clipboard.js/wiki/Known-IssuesOn IE9-11 there's a prompt that asks ...

  3. WARN [main] conf.HiveConf (HiveConf.java:initialize(1488)) - DEPRECATED

    问题描述:hive 关于告警问题的解决:WARN  [main] conf.HiveConf (HiveConf.java:initialize(1488)) - DEPRECATED: Config ...

  4. 五分钟看懂js关键字this

    this是js里面很常用的关键字,而灵活的js也赋予了这个关键字无穷的生命力,相信你也有被它糊弄的时候,我总结了一个6字原则,大部分场合都能清醒分辨this到底指向who,跟大家分享一下,欢迎指正. ...

  5. ecshop标签大全

    页面关键字:{$keywords}     页面标题:{$page_title}  产品分类:父分类列表 {foreach from=$categories item=cat }  父分类超链接 [u ...

  6. js 代码记录

    window.screen.availWidth 返回当前屏幕宽度(空白空间) window.screen.availHeight 返回当前屏幕高度(空白空间) window.screen.width ...

  7. Python 基础-python函数

    函数    1.def    2.命名    3.函数体    4.return 返回值 def get_return(): a = 1 return a 函数参数有 形参和实参    定义几个形参就 ...

  8. SSH config

    add  a file named 'config' , place in folder .ssh then you can use  "ssh yourname "quickly ...

  9. 计算广义积分$$\int_0^{+\infty}\cos x^p {\rm d}x,\int_0^{+\infty}\sin x^p {\rm d}x, p>1$$

    ${\bf 解:}$ 在角状域$G=\{z\in\mathbb{C}|0<{\rm Arg}z<\frac{\pi}{2p}\}$上引入辅助函数$e^{iz^p}$, 其中$z^p=|z| ...

  10. 只要是从事IT,会些CSS,XHTML总归是有好处的

    上次是十多年前看了的,这次又系统看了下.. 这系统的HEAD FIRST,我很喜欢...收藏过三四本啦...