/************************************************************************/
/* 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. [C++] 获取IE代理server的账号password

    非常多程序须要使用'浏览器设置'的代理server,IE设置的代理server有可能是须要账号password的.如何编程获取浏览器设置的代理server的账号password呢? InternetQ ...

  2. git 简单教程更新

    0.初始化 $ git config --global user.name "xxx" $ git config --global user.email "xxx@gma ...

  3. C# dll 事件执行 js 回调函数

      C# dll 事件执行 js 回调函数   前言: 由于js 远程请求  XMLHttpRequest() 不支持多线程,所以用C# 写了个dll 多线程远程抓住供js调用. 最初代码为: C#代 ...

  4. 数据结构二叉树的java实现,包括二叉树的创建、搜索、删除和遍历

    根据自己的学习体会并参考了一些网上的资料,以java写出了二叉树的创建.搜索.删除和遍历等操作,尚未实现的功能有:根据先序和中序遍历,得到后序遍历以及根据后序和中序遍历,得到先序遍历,以及获取栈的深度 ...

  5. Bootstrap 模态框

    Bootstrap 模态框(也可以说的弹出层) 最近在尝试使用bootstrap的模态框 使用模态框主要要引入一下几个js和css: bootstrap.css jquery.1.9.1.js(这个可 ...

  6. [转]网上看到的关于C中内存分配的描述

    1栈   -   有编译器自动分配释放     2堆   -   一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收     3全局区(静态区),全局变量和静态变量的存储是放在一块的,初始 ...

  7. 利用Matlab生成一个网格化的三维三轴椭球面(生成直角坐标)

    代码很简单,a,b,c分别为椭球的三轴轴长,a=b=c时得到的是三维球面,a=b!=c时得到的是三维椭球面,a!=b且a!=c且b!=c时得到的是三维旋转椭球面 %生成一个笛卡尔坐标系下三轴椭球表面的 ...

  8. JS逗号、冒号与括号

    JavaScript面试时候的坑洼沟洄——逗号.冒号与括号   看完了javaScript数据类型和表达式与运算符相关知识后以为可以对JavaScript笔试题牛刀小试一把了,没想到有一次次的死在逗号 ...

  9. malloc内存分配与free内存释放的原理

    malloc内存分配与free内存释放的原理 前段时间一直想看malloc的原理,在搜了好几篇malloc源码后遂放弃,晦涩难懂. 后来室友买了本深入理解计算机系统的书,原来上面有讲malloc的原理 ...

  10. 高级SQL特性

    SQL   SQL 必知必会·笔记<20>高级SQL特性 摘要: 约束(constraint)就是管理如何插入或处理数据库数据的规则.DBMS通过在数据库表上施加约束来实施引用完整性.1. ...