/************************************************************************/
/* 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. &lt;图形图像,动画,多媒体&gt; 读书笔记 --- 力学行为特性

    UIKit力学行为包括了:重力(UIGravityBehavior),碰撞(UICollisionBehavior),吸附(UIAttachmentBehavior),推(UIPushBehavior ...

  2. python进程池剖析(一)

    python中两个常用来处理进程的模块分别是subprocess和multiprocessing,其中subprocess通常用于执行外部程序,比如一些第三方应用程序,而不是Python程序.如果需要 ...

  3. Roslyn 编译平台概述

    在Language Feature Status上面看到,其实更新的并不是特别多,为了不会误导看了C# 6.0 功能预览 (一)的园友,现在把官方的更新列表拿了过来,供大家参考 C# 6.0 功能预览 ...

  4. SpecFlow

    SpecFlow http://blog.csdn.net/yujunwu2525/article/details/7839859 将业务需求与.NET代码结合起来 SpecFlow旨在弥合领域专家与 ...

  5. Dirichlet's Theorem on Arithmetic Progression

    poj3006 Dirichlet's Theorem on Arithmetic Progressions 很显然这是一题有关于素数的题目. 注意数据的范围,爆搜超时无误. 这里要用到筛选法求素数. ...

  6. Code First 启用迁移时出错 HRESULT:0x80131040

    问题:Enable-Migrations 使用“8”个参数调用“CreateInstanceFrom”时发生异常 (异常来自 HRESULT:0x80131040) PM> Enable-Mig ...

  7. Pi

    Math]Pi   数学知识忘地太快,在博客记录一下pi的生成. 100 Decimal places 3.1415926535897932384626433832795028841971693993 ...

  8. ACM STUDY

    ACM学习<二>   穷举算法思想:     一句话:就是从所有可能的情况,搜索出正确的答案. 步骤:     1.对于一种可能的情况,计算其结果.     2.判断结果是否满足,YES计 ...

  9. Hibernate:如何映射聚合?

    Hibernate:如何映射聚合? 目录 背景映射聚合聚合模型映射配置测试备注 背景返回目录 DDD 是在 Hibernate 之后发现的概念,Hibernate 如何映射 DDD 中的聚合呢?本文给 ...

  10. vim插件:显示树形目录插件NERDTree安装 和 使用

    下载和配置 NERDTree插件的官方地址如下,可以从这里获取最新的版本 https://github.com/scrooloose/nerdtree 下载zip安装包 或者使用下面官网源文件安装方法 ...