约瑟夫斯问题求解

合集下载

抽杀问题-约瑟夫问题

抽杀问题-约瑟夫问题

[阅读材料]世界名题与小升初之:抽杀问题(約瑟夫问题)--马到成功老师在各类竞赛中,各类小升初考试中相关的世界名题出现的概率极高,这是由小升初与数学竞赛的特点决定,这特点便是:知识性,趣味性,思想性相结合。

先给大家介绍这一问题的由来。

据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特後,39 個犹太人与Josephus及他的朋友躲到一個洞中,39個犹太人決定宁愿死也不要被人抓到,于是決定了一个自杀方式,41個人排成一个圆圈,由第1個人开始报数,每报数到第3人该人就必須自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他將朋友与自己安排在第16個与第31個位置,于是逃过了这场死亡游戏。

解法約瑟夫问题可用代数分析來求解,将这个问题扩大好了,假设现在您与m个朋友不幸参与了这个游戏,您要如何保护您的朋友?只要画两个圆圈就可以让自己与朋友免于死亡游戏,这两个圆圈是排列顺序,而外圈是自杀顺序,如下图所示:使用程式来求解的话,只要将阵列当作环状来处理就可以了,在列中由计数1开始,每找到三个无资料区就填入一个计数,直接计数來求解的話,只要將阵列当作环状来处理就可以了,在阵列中由計数1开始,每找到三个无资料区就填入一个計数,直而計数达41为止,然后將阵列由索引1开始列出,就可以得知每个位置的自杀順序,这就是約瑟夫排列,41個人报数3的約瑟夫排列如下所示:14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23由上可知,最后一個自杀的是在第31个位置,而倒数第二个自杀的要排在第16个位置,之前的人都死光了,所以他们也就不知道約瑟夫与他的朋友并没有遵守游戏规则了。

约瑟夫环问题(Josephus)

约瑟夫环问题(Josephus)

算法设计
Josephus jp=new Josephus(); int a[]=new int[n]; for(int i=0;i<n;i++){ a[i]=i+1; } jp.SortArray(a,n,m,k,g); } public void show(int[]b,int g){ for(int i=b.length-g;i<b.length;i++){ System.out.print(b[i]+" "); } }
• b[c]=a[i]; • a[i]=0; • c++; • if(c==n) break; • } • System.out.print(“最后出列的 3人: "); • this.show(b,g); • } • }
• 1.数据选择: 要求:n<2^15; 1<=k<=n; 2.数据和结果显示:
(3)当然其中还是会存在一些漏洞,需要进 一步的改进。在计算机中是容不得丝毫的 错误的,这也让我们学到了面对科学要持 有严谨的态度,否则必定得不到应该有的 结果。
总人数n 起始号码k 循环数m 最后出列的3人 总人数n 起始号码k 循环数m 最后出列的3人 总人数n 起始号码k 循环数m 最后出列的3人 48 6 15 47 21 46 105 73 4 87 32 21 300 80 12 70 296 198 总人数n 起始号码k 循环数m 68 34 25
输出格式:
T行最后min(n,3)个出列的编号。 结果:6 1 5
问题背景
• 这个问题是以弗拉维奥•约瑟夫斯命名的, 它是1世纪的一名犹太历史学家。他在自己 的日记中写道,他和他的40个战友被罗马 军队包围在洞中。他们讨论是自杀还是被 俘,最终决定自杀,并以抽签的方式决定 谁杀掉谁。约瑟夫斯和另外一个人是最后 两个留下的人。约瑟夫斯说服了那个人, 他们将向罗马军队投降,不再自杀。

约瑟夫问题

约瑟夫问题

一问题描述1 题目内容:约瑟夫(Joseph)问题的一种描述是:编号为1,2,..., n的n 个人按顺时针方向围坐一圈, 每人持有一个密码(正整数)。

一开始选任一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。

报m的人出列,将它的密码作为新的m值。

试设计一个程序求出出列顺序。

2 基本要求:利用单项循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

3 测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4(正确的出列顺序应为6,1,4,7,2,3,5)。

二需求分析程序运行后,首先要求用户指定初始报数上限值,然后读取个人的密码。

输入数据:建立输入处理输入数据,输入m的初值,n ,输入每个人的密码,建立单循环链表。

输出形式:建立一个输出函数,将正确的输出序列三概要设计利用单项循环链表存储结构模拟此过程1 循环链表的抽象数据类型循环链表是单链表的一种变化形式,把单链表的最后一个节点的next指针指向第一个节点,整个链表就形成了一个环。

2 循环链表的基本操作(仅列出用在本程序的)creat(n)操作结果:构造一个长度为n的无头节点的循环链表,并返回指向最后一个节点的指针find(m,s)初始条件:循环链表存在操作结果:找到当前元素(即s)后面第m个元素print(&m,&n,&s)初始条件:循环链表存在操作结果:从s中删除约舍夫问题中下一个被删除的元素,并将此元素显示在屏幕上3 本程序包括4个模块:主程序模块;创建循环链表模块;找节点模块;删节点模块;各模块调用关系如下图所示:4 约舍夫问题的伪码算法void main( ){输入参与的人数;输入第一个密码;创建无头节点的循环链表;输出第一个出列元素;输出剩余出列元素;}四详细设计1 实现概要设计的数据类型typedef struct LNode{int data;int num;struct LNode *next;}LNode,*linklist; //无头节点的循环链表的节点类型2 每个子函数的算法linklist creat(int n){/*构造一个长度为n的无头节点的循环链表,并返回指向最后一个节点的指针*/linklist head,s; //head为头节点标记s为链表中节点int i;s=head=(linklist)malloc(sizeof(LNode)); //创建头节点for(i=1;i<n;i++) //建立循环链表{s->data=i;printf("num%d: ",i);scanf("%d",&(s->num));/*输入第i个人的密码*/while(s->num<=0){/*如果输入的s->num小于等于0,要求重新输入*/ printf("请重新输入\nnum%d: ",i);scanf("%d",&s->num);}s->next=(linklist)malloc(sizeof(LNode)); //开辟下一个节点s=s->next;}s->data=i;printf("num%d: ",i);scanf("%d",&(s->num));s->next=head;return(s);}linklist find(int m,linklist s) //找到当前元素后面第m个元素{int i;for(i=0;i<m-1;i++)s=s->next;return(s); //返回找到元素的指针}void print(into &mint &n,linklist &s){linklist p;s=find(m,s); //找到待删除的元素printf("%d ",s->next->data);/*输出找到的元素*/m=s->next->num;/*将此元素从链表中删除,并释放此节点*/ p=s->next;s->next=s->next->next;free(p);--n; //约舍夫环中节点数少一}3 主程序算法void main( ){/*解决约舍夫问题的主函数*/int n,m; //n为约舍夫环内初始人数m为初始密码printf("type in n :");scanf("%d",&n);/*输入n*/while(n<=0){/*如果输入的n小于等于0,要求重新输入*/printf("please type n in again \ntype in n :");scanf("%d",&n);}printf("type in m :");scanf("%d",&m);/*输入m*/while(m<0){/*如果输入的m小于0,要求重新输入*/printf("please type m in again \ntype in m :");scanf("%d",&m);}linklist s;s=creat(n);/*创建无头节点的循环链表,返回指向最后一个元素的指针*/printf("the sequence is ");print(m,n,s);//输出第一个出列的元素while(n){print(m,n,s);//输出剩余出列的元素}printf("\n");}4 函数调用关系图五调试分析调试过程中出现过如下问题:1 开始编程序时没考虑输入错误的问题,导致输入错误后程序出错2 编程序时删除节点子程序结束条件出错3 对开辟的节点用完后没有释放六使用说明程序运行后按提示输入n和m的值,在输入约舍夫环中每个人的密码,运行即可得到出列顺序七测试结果进入程序后要求输入n的值然后输入m的值再输入每个人的密码最后得到出列顺序八附录(源程序)这里附上两种源程序,本质上相同,只是第一个程序按老师要求写为很多子函数形式,第二个是我已开始编的,一个大函数。

实验报告 约瑟夫问题

实验报告 约瑟夫问题
pNew->next = pCur->next;
pCur->next = pNew;
pCur = pNew;
printf("结点%d,密码%d\n",pCur->id, pCur->cipher);
}
}
printf("完成单向循环链表的创建!\n");
}
(3)运行"约瑟夫环"问题
static void StartJoseph(NodeType **, int)
exit(-1);
}
pNew->id = iId;
pNew->cipher = iCipher;
pNew->next = NULL;
return pNew;
}
(6)测试链表是否为空,空为TRUE,非空为FALSE
static unsigned EmptyList(const NodeType *pHead)
实验内容
利用循环链表实现约瑟夫环求解。
实验说明
1.问题描述
约瑟夫问题的:编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
{
if(!pHead)
{
return TRUE;
}
return FALSE;
}
实验中遇到的问题及解决方法
实验结果如下:
实验总结(结果和心得体会)

约瑟夫问题多种解决方法

约瑟夫问题多种解决方法

• • • • • • • • • • •
s:=0; while s<n do begin if j<m then inc(j) else j:=1; s:=s+a[j]; end; write(j); a[j]:=0; end; end.

约瑟夫问题多 种解决方法
约瑟夫问题的来历
• 据说著名犹太历史学家 Josephus有过以下的故事:在罗 马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋 友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓 到,于是决定了一个自杀方式,41个人排成一个圆圈,由 第1个人开始报数,每报数到第3人该人就必须自杀,然后 再由下一个重新报数,直到所有人都自杀身亡为止。然而 Josephus 和他的朋友并不想遵从,Josephus要他的朋友 先假装遵从,他将朋友与自己安排在第16个与第31个位置, 于是逃过了这场死亡游戏。17世纪的法国数学家加斯帕在 《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余 的人才能幸免于难,于是想了一个办法:30个人围成一圆 圈,从第一个人开始依次报数,每数到第九个人就将他扔 入大海,如此循环进行直到仅余15个人为止。问怎样排法, 才能使每次投入大海的都是非教徒。
著名约瑟夫问题一
• 17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了 这样一个故事:15个教徒和15 个非教徒在深海上遇险, 必须将一半的人投入海中,其余的人才能幸免于难,于是 想了一个办法:30个人围成一圆圈,从第一个人开始依次 报数,每数到第九个人就将他扔入大海,如此循环进行直 到仅余15个人为止。问怎样排法,才能使每次投入大海的 都是非教徒。题目中30个人围成一圈,因而启发我们用一 个循环的链来表示。可以使用结构数组来构成一个循环链。 结构中有两个成员,其一为指向下一个人的指针,以构成 环形的链;其二为该人是否被扔下海的标记,为1表示还 在船上。从第一个人开始对还未扔下海的人进行计数,每 数到9时,将结构中的标记改为0,表示该人已被扔下海了。 这样循环计数直到有15个人被扔下海为止

约瑟夫问题的经典三个例子

约瑟夫问题的经典三个例子

约瑟夫问题的经典三个例子以下是 9 条关于约瑟夫问题的经典例子:例子 1:想想看,一群小朋友围成一圈玩游戏,就像我们小时候那样。

这时候说从某个小朋友开始报数,每隔一个人淘汰,最后剩下的那个就是胜利者。

这不就是约瑟夫问题嘛。

就好像在一个神秘的游戏圈子里,大家都紧张又兴奋地等待着命运的裁决。

例子 2:你能想象军队里士兵们站成一圈,然后用这种方式来决定谁去执行特殊任务吗?哎呀呀,那场面肯定很刺激。

每个士兵心里都七上八下的,不知道自己是不是那个“幸运儿”,这和约瑟夫问题如出一辙。

例子 3:假如在一场盛大的聚会中,大家玩这样的游戏,是不是超级有趣?就像一个魔法圈,把大家的注意力都吸引过来了。

每淘汰一个人,大家就会一阵惊呼,这不正是约瑟夫问题带来的独特体验嘛。

例子 4:你看过那种生存挑战节目吗?选手们围成一圈,然后通过类似约瑟夫问题的规则来淘汰人。

哇塞,那紧张的氛围,可不就是在经历一场残酷的竞争,这就是约瑟夫问题在现实中的精彩呈现呀!例子5:好比一群探险家在荒岛上,为了分配重要资源而采取这种方式。

每个人都祈祷自己不要被先淘汰掉,这种感觉是不是很奇妙?这就是约瑟夫问题带来的不确定性啊。

例子6:想象一下公司团建的时候玩这个,大家既期待又担心。

“哎呀,可别先轮到我呀!”“哇,我居然留下来了。

”这种种反应,不就是约瑟夫问题的魅力所在吗?例子 7:学校运动会上,各班学生围成一圈进行比赛,多刺激呀!有人欢喜有人忧,这不就是约瑟夫问题所引发的情绪波澜吗?例子 8:在一个神秘的魔法学院里,学生们也用这种方式来选拔优秀学员。

每一个人都全神贯注,这和约瑟夫问题一样充满了悬念呢!例子9:如果在一个古老的部落中,用约瑟夫问题来决定首领的继承人,那该是多么惊心动魄的场面啊。

大家的心都提到了嗓子眼,。

约瑟夫问题

约瑟夫问题

4、狐狸捉兔子
题目:
围绕着山顶有10个洞,狐狸要吃兔子,兔子说:“可以,但必须找到我,我就藏身于这十个洞中,你从10号洞出发,先到1号洞找,第二次隔1个洞找,第三次隔2个洞找,以后如此类推,次数不限。”但狐狸从早到晚进进出出了1000次,仍没有找到兔子。问兔子究竟藏在哪个洞里?
参考程序下载
--------------------------------------------------------------------------------
5、进制转换
题目:
将一个十进制自然数转换成二进制数,一般采取除2取余法。从键盘输入一个十进制自然数(约定该数小于等于Maxlongint),输出相应的二进制数
设有一天平,可用来称物体的质量,同时给出一个正整数n(n<=10)。
问题1:试设计n个砝码的质量,用它们能称出尽可能多的1,2,3,...连续整数质量,约定砝码可以放在天平的左右两个托盘中的任何一个或两个中。例如n=2,此时设计2个砝码的质量分别为1,3,则能同时称取1,2,3,4。
问题2:在给出n个砝码能称出最大质量范围内的一个质量x,试给出称取x的方案。如上例中:
6/7,7/8,1/1
编程求出n级法雷序列,每行输出10个分数。n的值从键盘输入。
--------------------------------------------------------------------------------
13、砝码设计
题目:
①把组成这个四位数的4个数字由小到大排列,形成由这四个数字组成的最大的四位数;
②把组成这个四位数的4个数字由大到小排列,形成由这四个数字组成的最小的四位数(如果含有数字0,则不足四位);

线段树-约瑟夫问题 题+题解

线段树-约瑟夫问题 题+题解

Wikioi : 1282 约瑟夫问题题目描述Description有编号从1到N的N个小朋友在玩一种出圈的游戏。

开始时N个小朋友围成一圈,编号为I+1的小朋友站在编号为I小朋友左边。

编号为1的小朋友站在编号为N的小朋友左边。

首先编号为1的小朋友开始报数,接着站在左边的小朋友顺序报数,直到数到某个数字M时就出圈。

直到只剩下1个小朋友,则游戏完毕。

现在给定N,M,求N个小朋友的出圈顺序。

输入描述Input Description唯一的一行包含两个整数N,M。

(1<=N,M<=30000)输出描述Output Description唯一的一行包含N个整数,每两个整数中间用空格隔开,第I个整数表示第I个出圈的小朋友的编号。

分析:由题意也可以看出,算法明确的分为两部分:模拟约瑟夫+ 求取原始序号。

1. 约瑟夫模拟:使用相对坐标(相对于环内),例如当前被踢位置为k,下一个被踢的是+m,则k被踢掉以后,原本的k+1就成了k(相对坐标嘛)。

这样下一个位置就应该是新K + m-1 。

再考虑到循环意义:next = (k + m-1 - 1) % 人数+ 1。

当m为负向时,同理,只是要注意保证求得的下一次位置值是个正值。

2. 取原始序号:这个直接看下面的代码( update() )Code:#include <iostream>#include <cstdio>using namespace std;#define LL long longconst int N = 30001*4;#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1int sum[N<<2];int tree[N<<2][2];void PushUp(int rt){sum[rt] = sum[rt<<1] + sum[rt<<1|1];}void build(int l,int r,int rt){tree[rt][0] = l;tree[rt][1] = r;if(l == r){sum[rt] = 1;return;}int m = (l+r)>>1;build(lson);build(rson);PushUp(rt);}int update(int p,int rt){sum[rt] --;if(tree[rt][0] == tree[rt][1]){sum[rt] = 0;return tree[rt][0];//从绝对位置剔除}if(p <= sum[rt<<1]) return update(p,rt<<1);else return update(p-sum[rt<<1],rt<<1|1);PushUp(rt);}int main(){int n,m;scanf("%d%d",&n,&m);build(1,n,1);int pos = 1;int seq = 1;for(int i = 0 ; i < n ; i++){seq = (seq + m - 1) % sum[1];//seq 只是相对位置if(seq == 0) seq = sum[1];pos = update(seq,1);cout<<pos<<" ";}return 0;}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验一:约瑟夫斯问题求解一、问题描述1.实验题目:约瑟夫斯问题的一种描述是:编号为1,2,……n的n个人按顺时针方向围坐一圈,每人持有一个密码9(正整数)。

一开始任选一个正整数作为报数上限值m,从第一个人开始按照顺时针方向自1开始报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新重新从1报数,如此下去,直至所有的人全部出列为止。

试设计一个程序,按出列顺序印出各人编号。

2.基本要求:利用单向循环链表模拟此过程,按照出列的顺序印出各人编号。

3.测试数据:n=7,7个人的密码依次为3,1,7,2,4,8,4.m的初始值为6(正确的出列顺序应为6,1,4,7,2,3,5。

二、需求分析1.程序所能达到的基本可能:本程序能够按出列顺序印出各人编号,程序运行后显示提示信息,提示用户输入人数n,初始报数值m,n个人的密码,程序需自动考虑重复的,用户输入完毕后,程序自动输出运算结果。

2.输入的形式及输入值范围:输入人数n,初始报数值m,n个人的密码,所有值均为正整数int型。

3.输出的形式:输出的是按出列顺序印出各人编号,为正整数int型。

4.测试数据要求:测试数据要求为int型三、概要设计1. 所用到得数据结构及其ADT为了实现上述功能,应以单向循环链表有序链表表示集合数据类型。

1. 单向循环链表抽象数据类型定义:typedef struct node{ElemType data;ElemType num;struct node *next;}SLNODE;基本操作:struct node *create_sl(int n);//创建单向循环链表2.主程序流程及其模块调用关系1)创建循环链表的流程图2)约瑟夫问题求解流程图3)主函数流程图四、详细设计1. 实现每个操作的伪码,重点语句加注释主程序:void main(){SLNODE *head;int n,m;head=(SLNODE *)malloc(sizeof(SLNODE));printf("/*************************************/\n"); //初始界面 printf(" 学号:031350102\n");printf(" 姓名:王亚文\n");printf(" 约瑟夫斯问题求解\n");printf("/*************************************/\n");printf("输入总人数n=\n");scanf("%d",&n);printf("输入初始报数值m=\n");scanf("%d",&m);head=create_sl(n);Josephus(head,n,m);}2.创建循环单链表struct node *create_sl(int n){SLNODE *p,*s,*head;ElemType x;int a;head=(SLNODE *)malloc(sizeof(SLNODE));p=head;head->next=head;for(a=1;a<=n;a++) //循环直到输入n个密码值跳出循环 {s=(SLNODE *)malloc(sizeof(SLNODE));printf("请输入第%d个人的密码值\n",a);scanf("%d",&x);s->data=x;s->num=a;if(head->next==head) head=s;else p->next=s;p=s;}p->next=head;return head;}3.约瑟夫斯问题求解:void Josephus(SLNODE *head,int n,int m){SLNODE *p,*q;int i;p=head;printf("出列序列:");while(p->next!=p){for(i=1;i<m;i++) //报数报的m时跳出循环{q=p;p=p->next;}m=p->data; //读取新的密码值printf("%4d",p->num);q->next=p->next; //删除p节点free(p);p=q->next;}printf("%4d\n",p->num);}4. 函数调用关系图主函数中调用了struct node *create_sl(int n);void Josephus(SLNODE *head,int n,int m);两个函数五、调试分析1. 设计与调试过程中遇到的问题分析、体会1)创建单链表时,一开始写的程序是void create_sl(SLNODE *head ,int n),并没有没有报错,但最后运行时却不是想象的结果,然后尝试在主函数中写一个printf函数看一下创建表是否创建成功,事实证明并没有,后来改成了struct node *create_sl(int n);解决了这个问题,再次就是建表的时候发现最后一个数并不是我输入的数,然后就是开始改那个循环=函数,发现我虽然是读了7个数,但第7个数并没有赋值给链表,原错误函数:p=head;head->next=head;printf("请输入密码值\n");scanf("%d",&x);for(a=1;a<n;a++) //循环直到输入n个密码值跳出循环{s=(SLNODE *)malloc(sizeof(SLNODE));printf("请输入密码值\n");scanf("%d",&x);s->data=x;s->num=a;if(head->next==head) head=s;else p->next=s;p=s;}经过修正后的函数:p=head;head->next=head;for(a=1;a<=n;a++) //循环直到输入n个密码值跳出循环{s=(SLNODE *)malloc(sizeof(SLNODE));printf("请输入第%d个人的密码值\n",a);scanf("%d",&x);s->data=x;s->num=a;if(head->next==head) head=s;else p->next=s;p=s;}2)建表成功之后开始解决本次的主问题约瑟夫斯求解问题,本问题主要考虑循环终止条件,一开始写的是head->next=head;发现经常运行错误,后来修正用p->next!=p,然后最后一个p值单独写一句输出printf("%4d\n",p->num);中间的句子就是找到报数值然后删除,注意保留要删除节点的密码值,并没有什么大问题。

还有一个问题,就是在开始的时候创建单链表并没有想到要用序号值num,最开始定义单链表的语句:typedef struct node{ElemType data;struct node *next;}SLNODE; 然后就会在创建链表赋值时和解决约瑟夫斯问题时都要重新定义一个变量x进行计数,增加了程序的复杂度最后修正为:typedef struct node{ElemType data;ElemType num;struct node *next;}SLNODE;3)剩下的还有一些小问题,比如少打了一个字母,打错一个字母,这些程序会报错,不属于逻辑错误,所以解决起来也比较快,2. 主要算法的时间复杂度分析创建单链表的时间复杂度为O(n);约瑟夫斯问题的时间复杂度与n值有关,也与每个人的密码值有关,时间复杂度O(mn);空间复杂度为O(n);六、使用说明程序运行后显示提示信息,提示用户输入人数n,初始报数值m,n个人的密码,用户按照提示输入完毕后,程序自动输出运算结果。

七、测试结果八、附录#include <stdio.h>#include <malloc.h>#include <stdlib.h>#include <time.h>typedef int ElemType;typedef struct node{ElemType data;ElemType num;struct node *next;}SLNODE; //单链表的定义struct node *create_sl(int n);void Josephus(SLNODE *head,int n,int m);int main() //主函数{SLNODE *head;int n,m;time_t rawtime;struct tm * timeinfo;time (&rawtime);timeinfo = localtime (&rawtime);head=(SLNODE *)malloc(sizeof(SLNODE));printf("/*************************************/\n"); //初始界面printf(" 学号:031350102\n");printf(" 姓名:王亚文\n");printf(" 约瑟夫斯问题求解\n");printf("/*************************************/\n");printf("输入总人数n=\n");scanf("%d",&n);printf("输入初始报数值m=\n");scanf("%d",&m);head=create_sl(n); //创建单链表Josephus(head,n,m);printf ("Current local time and date: %s", asctime(timeinfo)); return 0;}struct node *create_sl(int n){SLNODE *p,*s,*head;ElemType x;int a;head=(SLNODE *)malloc(sizeof(SLNODE));p=head;head->next=head;for(a=1;a<=n;a++) //循环直到输入n个密码值跳出循环 {s=(SLNODE *)malloc(sizeof(SLNODE));printf("请输入第%d个人的密码值\n",a);scanf("%d",&x);s->data=x;s->num=a;if(head->next==head) head=s;else p->next=s;p=s;}p->next=head;return head;}void Josephus(SLNODE *head,int n,int m)//约瑟夫斯问题求解{SLNODE *p,*q;int i;p=head;printf("出列序列:");while(p->next!=p){for(i=1;i<m;i++) //程序运行到第m个人跳出循环{q=p;p=p->next;}m=p->data; //读取新的密码值printf("%4d",p->num);q->next=p->next; //删除p节点free(p);p=q->next;}printf("%4d\n",p->num);}九、实验收获和感想通过本实验首先是解决了约瑟夫斯问题,利用计算机快速解决这个问题,其次在程序编写过程中慢慢掌握了循环单链表的一些用法以及注意事项,因为距离上次学习c语言已经有很长一段时间,这次确实遇到了很多障碍,不仅仅是对链表的生疏,也包含以前基础的薄弱环节,通过一个程序的设计,慢慢回忆起程序的编写,加强自己的逻辑性,编程是一个很麻烦的事,一个小错误的出项,程序就不会出现预想的结果,如果报错还可以按照提示找到,若有逻辑错误还得一行一行检查,最后发现如果程序需要解决多个问题,最好还是分模块解决,解决完一个问题再去解决另一个问题,如果一个模块有错误及时发现,也比较好改。

相关文档
最新文档