/************************************************************************/
/* Josephus问题——数组实现 */
/************************************************************************/
#include <stdio.h>
#include <malloc.h> int Josephus(int times, int number, int id){
int *a;
int i, count = , t = ;
a = (int *)malloc(sizeof(int) * number); for(i = ; i < number; i++)
a[i] = i + ; // 数组a用于储存每个元素的编号
i = id - ; while(count < number - ){
if(a[i] != )
t++;
if(t == times){
t = ;
count++;
printf("%4d", a[i]);
a[i] = ; // 当该元素被剔除时,该数组元素置为0
}
i++;
if(i == number)
i = ;
}
for(i=;i<number;i++)
if(a[i]!=)
{
printf("\n最后剩余的结点是:%4d\n",a[i]);
return;
} } int main(){
int times, number, id;
printf("请输入总人数:");
scanf("%d", &number);
printf("请输入报数周期:");
scanf("%d", &times);
printf("请输入开始报数的编号:");
scanf("%d", &id);
Josephus(times, number, id); return ;
} /************************************************************************/
/* 总结:
优点为可以得出每次被剔除的元素编号
缺点为内存空间占用较大,没有数学归纳法快速 */
/************************************************************************/ /************************************************************************/
/* Josephus问题——循环链表实现 */
/************************************************************************/
#include <stdio.h>
#include <malloc.h> typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*Linkhead;
void Josephus(int m,int n,int k)
{
Linkhead p,r,head = NULL;
int i;
for(i = ;i <= n;i++)
{
p = (Linkhead)malloc(sizeof(LNode));//申请一个新的链结点
p->data = i;//存放第i个结点的编号
if(head == NULL)
head = p;
else
r->next = p; // 因为Insert和Del操作都需要之前一个节点的地址,故用r来存储。其作用类似栈的top
r = p;
}
p->next = head;//至此,建立一个循环链表 p = head;
for(i = ;i < k;i++)
{
r=p;
/*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
p=p->next;
} //此时p指向第1个出发结点 while(p->next != p)
{
for(i = ;i < m;i++)
{
r = p;
p = p->next;
} //p指向第m个结点,r指向第m-1个结点
r->next = p->next; //删除第m个结点
printf("%4d",p->data); //依次输出删除结点的编号
free(p); //释放被删除结点的空间
p = r->next; //p指向新的出发结点
}
printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
} int main(){
int times, number, id;
printf("请输入总人数:");
scanf("%d", &number);
printf("请输入报数周期:");
scanf("%d", &times);
printf("请输入开始报数的编号:");
scanf("%d", &id);
Josephus(times, number, id); return ;
} /************************************************************************/
/* 总结:
优点为可以得出每次被剔除的元素编号
缺点为相较数组方法需要更多的计算量
总体而言与数组方法相差无几 */
/************************************************************************/ /************************************************************************/
/* Josephus问题——数学归纳法直接计算 */
/************************************************************************/
#include <stdio.h>
int main() {
int answer = ;
int times, number, i, id; // number为环内总元素个数,times为报数周期, id为从第几个元素开始报数
printf("请分别输入总人数和循环次数:");
scanf("%d %d", &number, &times);
printf("起始报号者的编号:");
scanf("%d", &id);
for(i = ; i <= number; i++) {
answer = (answer + times) % i; // 核心算法,利用数学归纳法得出
}
if(answer + id == number)
printf("Survial: %d\n", number); // 防止当幸存者为最后一个编号时输出0的情况
else
printf("Survival: %d\n",(answer + id) % number);
// 这边利用number对answer进行取余操作以防止编号数值超过最大编号(溢出) return ;
}
对于Josephus问题有两个地方是可以进行优化的。 (总人数为N,编号为从0~N-1;经过M次报数去除一个成员,剩余成员个数为numleft, 记M%numleft为mPrime)

 1、被移除的成员离上一个成员之间的距离是M%numleft-1(报数次为M%numleft).当M大于N时,该计算方式将节省大量时间
 2、当mPrime大于numleft的时候可以反向遍历该表来查找要去除的成员。这样可以节省时间。同样这也就要求了该表必须是一个双向表才行。(即含有Previous方法)
  该算法实现原理即为:

  第一轮,必定为编号M%N-1的成员被去除,第二轮为在第一轮的基础上即从编号为M%N的成员开始正移mPrime-1个单位(或者反移numleft-mPrime-1个单位)。若将M%N即为编号0,开始重新编号,那么第二轮被删除的成员编号便是M%(numleft)-1,由此可得该轮要被删除的成员与上一轮去除成员之间的距离为M%numleft,这里可利用迭代器来实现。

  这里我们便可以得到成员编号与该轮成员数目的关系是:(n表示该轮所剩余的成员数目,Index(n)表示该轮成员的编号(从0开始))
Index(n) = (Index(n - 1) + m) % n。
那么按照这个过程,我们这样一直移除元素下去,肯定能够找到最后一个被移除的元素。
这个元素则对应只有一个元素的环,很显然,它的值为0。也就是Index(1) = 0。
对于这个元素的索引,它对应两个元素的索引是多少呢?
按照前面的过程,我们倒推回去就是了。Index(2) = (Index(1) + m) % 2。
那么对应3个,4个元素的呢?我们这样一路继续下去就可以找到对应到n个元素的索引了。
所以,我们发现了一个有意思的数学归纳关系:
f(1) = 0, f(n) = (f(n - 1) + m) % n。
按照这个关系,我们可以得到最后一个被取出来的元素对应到n个元素的环里的索引值。 至此,我们可以发现,利用count计数从而删除成员的方法与此相比起来逊色不少,故之后我们将采用此方法来解决问题。
该问题的最终解决程序可参见另一篇文章:

Josephus问题的java实现

 

Josephus问题的不同实现方法与总结的更多相关文章

  1. Josephus问题的java实现

    import java.util.ArrayList; import java.util.ListIterator; public class Josephus { public static voi ...

  2. javaSE27天复习总结

    JAVA学习总结    2 第一天    2 1:计算机概述(了解)    2 (1)计算机    2 (2)计算机硬件    2 (3)计算机软件    2 (4)软件开发(理解)    2 (5) ...

  3. Josephus环问题

    约瑟夫环问题 问题描述: Josephus问题可以描述为如下的一个游戏:N个人编号从1到N,围坐成一个圆圈,从1号开始传递一个热土豆,经过M次传递后拿着土豆的人离开圈子,由坐在离开的人的后面的人拿起热 ...

  4. josephus问题

    问题描述 n个人围成一圈,号码为1-n,从1开始报数,报到2的退出,剩下的继续从1开始报数,求最后一个人的号码. 算法分析 最直观的算法是用循环链表模拟.从首节点开始,不断删除第二个节点,直到只剩一个 ...

  5. 约瑟夫问题(Josephus Problem)的两种快速递归算法

    博文链接:http://haoyuanliu.github.io/2016/04/18/Josephus/ 对,我是来骗访问量的!O(∩_∩)O~~ 约瑟夫问题(Josephus Problem)也称 ...

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

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

  7. 约瑟夫(Josephus)问题~转

    本文都是转的,一个是转博客,一个是转贴吧,前者详细,后者"强,无敌"! 博客转: 以前就知道约瑟夫问题是模拟,今天我才发现一些约瑟夫问题可以使用数学解法得出!真是强悍啊!约瑟夫问题 ...

  8. 谁能笑到最后,约瑟夫环-Josephus问题求解

     一. 简述Josephus问题 N个人站成一环,从1号开始,用刀将环中后面一个人“消灭“”掉,之后再将刀递给下一个人,这样依次处理,最后留下一个幸存者. 二. 求解方法  1.  约瑟夫问题如果使用 ...

  9. mapreduce多文件输出的两方法

    mapreduce多文件输出的两方法   package duogemap;   import java.io.IOException;   import org.apache.hadoop.conf ...

随机推荐

  1. WPF随手小记之二 ——改变DataGrid样式

    大部分时候我们并不需要手动改变DataGrid的样式,因为用默认的其实也看得过去,而且在DataGrid中的数据也远比外观重要. 但总有时候,我们需要做点必要的UI修改来使DataGrid更美观. 一 ...

  2. ComponentName意思

    ComponentNameActivity Intent i=new Intent(); i.setComponent(new ComponentName(String packageName,Str ...

  3. 让Xcode Lua 语法高亮

    本人不太喜欢用code ide 还是喜欢XCODE的风格 1.让Xcode支援Lua语法高亮(Syntax Highlighting) 1. 下载https://github.com/breinhar ...

  4. 关于readonly

    当某个字段是引用类型,且该字段是readonly类型时,那么不可改变的是引用,而非引用的对象.如以下代码: public sealed class AType { public static read ...

  5. script —— 终端里的记录器

    当 你在终端或者控制台工作时,你可能想要记录在终端中所做的一切.这些记录可以用来当作史料,保存终端所发生的一切.比如说,你和一些Linux管理员们同 时管理着相同的机器,或者你让某人远程登陆到了你的服 ...

  6. 玩转python之字符串逐个字符或逐词反转

    众所周知,python中的字符串是无法改变的,反转一个字符串自然要创建一个拷贝:最简单的方法,当然是步长为“-1”的切片: result = astring[::-1] 如果要是按单词来反转,需要三步 ...

  7. MVC应用程序请求密码的功能1

    MVC应用程序请求密码的功能(一) 经过一系列的练习,实现了会员注册<MVC会员注册>http://www.cnblogs.com/insus/p/3439599.html,登录<M ...

  8. Twitter算法

    算法实践——Twitter算法面试题(积水问题)的线性时间解法   问题描述:在下图里我们有不同高度的挡板.这个图片由一个整数数组所代表,数组中每个数是墙的高度.下图可以表示为数组(2.5.1.2.3 ...

  9. FAQ:仓储实现为什么在基础设施层?

    FAQ:仓储实现为什么在基础设施层? 目录 问答部分参考文章 问答部分返回目录 问: 仓储实现为什么在基础设施层? 答: 领域模型包含三种元素:实体.值对象和服务,这三种元素都可以以某种形式使用仓储, ...

  10. 核心C#

    核心C# 内容提要: 声明变量:变量的初始化和作用域:C#的预定义数据类型:在C#程序中使用条件语句.循环和跳转语句指定执行流:枚举:名称空间: Main()方法:基本命令行C#编译器选项:使用Sys ...