约瑟夫斯问题
实验报告 约瑟夫问题

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个人被扔下海为止
实验一、约瑟夫问题

实验一:约瑟夫问题求解一、问题描述1、实验题目:约瑟夫(Josephus)问题的一种描述是:编号为1,2,……,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上线值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。
2、基本要求:试设计一个程序,按出列顺序印出个人编号。
3、测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4。
m的初值为6,正确的出列顺序应为:6,1,4,7,2,3,5。
二、需求分析1、本程序用来求出含有密码的约瑟夫问题,可以输出所有人的出列顺序。
2 、程序运行后显示提示信息,提示用户输入一圈的人数n,接着输入每个人的密码,最后提示输入初始密码。
3、用户输入完毕后,程序自动输出运算结果。
三、概要设计1、设计思路n个人围成一圈,每个人的手中都有一个密码,这个密码决定了下一次报数的上限。
游戏规则:①给定一个初始密码②循环报数,报到密码值的人要出列,依次类推,直到所有的人都出列本程序要求输入的内容:n个人的密码及初始密码;本程序要求输出的内容:n个人出列的顺序。
2、数据结构为了实现上述功能,可以采用链式存储结构。
采用链式存储结构,定义了一个存储个人信息的结构体,及两个自定义函数,分别用于创建链表和约瑟夫出列操作。
①链表抽象数据类型的定义: #define SLNODE struct slnodeADT SLNODE{数据对象:D={ i a |i a ∈SLNODE, i=1,2,3.... }数据关系:R=φ}ADT SLNODE;②自定义函数:void create_SLnode(SLNODE *p,int n)//创建队列{ 创建链表,为N 个人分配密码 }void Josef(SLNODE *p,int n)//进行约瑟夫操作{输入初始密码m;for(){ 将出列的结点删除,并输出出列序号;}}③本程序的保护模块:结构体模块主程序模块自定义函数模块调用关系:3、程序设计主要算法的流程图:create_SLnode( )算法流程图Josef( )算法流程图四、详细设计1、元素类型、结点的类型及指针#define SLNODE struct slnodeSLNODE//每个结点的结构体{int num;//num代表序号int code;//code代表密码SLNODE *next;};2、自定义函数:void create_SLnode(SLNODE *p,int n)//创建队列,并将其尾指针指向第一个序号{SLNODE *r,*s;s=p;int i,m;cout<<"请给这"<<n<<"个人分配密码:"<<endl;for(i=0;i<n;i++){cout<<"请给第"<<i+1<<"个人输入密码:"<<endl;cin>>m;r=(SLNODE *)malloc(sizeof(SLNODE));r->code=m;r->num=i+1;r->next=s->next;s->next=r;s=s->next;}p=p->next;s->next=p;}void Josef(SLNODE *p,int n)//进行约瑟夫操作{p=p->next;int m;int i,j;SLNODE *r;cout<<"请输入初始密码:"<<endl;cin>>m;cout<<"依次出列的序号为:"<<endl;for(i=0;i<n-1;i++)p=p->next;for(i=0;i<n-2;i++){for(j=0;j<m-1;j++)p=p->next;cout<<(p->next)->num<<endl;m=(p->next)->code;r=p->next;p->next=r->next;}if(m%2==0)cout<<p->num<<endl<<(p->next)->num<<endl;elsecout<<(p->next)->num<<endl<<p->num<<endl;}3、主函数:int main(){SLNODE *p;int n;cout<<"请输入一圈的人数:"<<endl;cin>>n;p=(SLNODE *)malloc(sizeof(SLNODE));p->next=NULL;create_SLnode(p,n);Josef(p,n);return 0;}4、函数的调用关系:主函数main()调用自定义函数void create_SLnode(SLNODE *p,int n);/*创建队列*/与void Josef(SLNODE *p,int n);/*进行约瑟夫操作*/。
“约瑟夫斯问题”背景下的变式探究

右边后再从右边开 始依次剔 除第 一个, 第三个, 每隔一个剔除一人; 再从左边按同样规则, 至最 后剩下一人继承王位, 求此人的编号.
不等式 () 木还可以变形为
已知X 、 为正数, 、Y 求证: y ( + x z≥ Y 一
≤ 1 .
( 16 一 (1) n — (1)+一 + )+ c 1
) + ) ( 一 ( +Y . …… … … (术 — )… … … …・ ) 术
这是 18 年瑞士数学竞赛试题. 93 把此不等式变形, 就有
到下面的定理.
解: 由推论知: 约瑟夫斯的编号为 2×(2一 5
3) O 2 =4 .
三、 定理 将 123 … ,n , ,, 2 排成 圆周, 依次取 出 1 3 ,,
5… , , 每隔一个取一数, 则最后取出的是 2 . n
例 2 (00 20 年美 国邀 请赛) 标号为 1 2 3 , ,, … , 00 20 的一 叠纸牌 排成 圆周, 若把 1 号取 出,
3 … , , , 2 则最后取出的编号Ln一1满足 ( ) 2( L n一1 = n, () , () , , ) ()而L 1 =2 L2 =4 … 故L n =2 . () 礼 四、 问题 的变式探究
1改变人数 “n型” 扎型” 探 求问题 _ 2 为“ ,
令他们排成 圆圈, 分别编号 1 2 3 … , 2 然后 ,,, 3,
解: 每经一步少两个数, 若经P 步至最后只剩 个数, 必有 礼= 2 p+ 1 .由和为 的3 个数,
经3 步后剩下3 个数, 和仍为 S 至最后只 ,
剩一个数时, 写出的所有数总和为( 十1s 而 ),
5 1= 3 +2 , 1 步后剩下 3 个数, 3 4经 2 0 被划去
约瑟夫问题(报数问题)

约瑟夫问题(报数问题)约瑟夫问题(报数问题)起因:据说著名犹太历史学家Josephus有过以下的故事:在罗⻢⼈占领乔塔帕特后,39个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓到,于是决定了⼀个⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
然⽽Josephus 和他的朋友并不想遵从。
⾸先从⼀个⼈开始,越过k-2个⼈(因为第⼀个⼈已经被越过),并杀掉第k个⼈。
接着,再越过k-1个⼈,并杀掉第k个⼈。
这个过程沿着圆圈⼀直进⾏,直到最终只剩下⼀个⼈留下,这个⼈就可以继续活着。
问题是,给定了和,⼀开始要站在什么地⽅才能避免被处决。
Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。
中,类似问题⼜称为约瑟夫环,⼜约瑟夫问题,是⼀个和中的问题,在计算机的中,类似问题⼜称为约瑟夫环,⼜约瑟夫问题,是⼀个和中的问题,在计算机的称“丢⼿绢问题”。
及过程就是先决定⼀个判断数字为k,若第⼀个⼈从⼀开始报数,若报数到k,则第k个⼈就要出来,从第k+1个⼈,⼜重新开始从⼀开始报数,报的K的⼈再次出队,若所有⼈都报过⼀遍,则从第⼀个⼈开始循环,依次类推。
直到只剩下⼀个⼈为⽌。
解题步骤:可以将约瑟夫问题看成⼩朋友循环排队的⽅法。
⼩朋友们排成⼀队,每⼀位⼩朋友报数结束后,如果报的数不是出队的数(判断数字k),则⾃动到对尾排队,如果等于出队数,这个⼩朋友出队。
⼀直循环,直到剩下⼀个⼩朋友为⽌//这是判断数字为3的时候,其他的类似//item=int(input())a=[]num1=0num2=3for i in range(1,item+1):a.append(i)while len(a)>1:num1+=1t=a.pop(0)if num1!=3:a.append(t)else:num1=0print(a[0])举⼀反三:若不确定让⽤户随意输⼊判断数item,m=map(int,input().split(''))a=[]num1=0num2=3for i in range(1,item+1):a.append(i)while len(a)>1:num1+=1t=a.pop(0)if num1!=m:a.append(t)else:num1=0print(a[0])这⾥使⽤while会更加简单⼀些,⽐⽤for-in循环更好写。
约瑟总结范文

约瑟总结引言约瑟总结(Josephus problem)是一个古老而著名的数学问题。
根据传说,约瑟夫是一群40个士兵的领导者,他们被敌军包围。
为了避免被俘,他们决定在自杀和投降之间进行选择。
士兵们排成一个圆圈,并从一个指定的位置开始依次报数,报到指定的数目的人就被处决。
然后,下一个人重新报数。
这个过程一直进行,直到只剩下一个人幸存为止。
解决方法约瑟夫问题是一个经典的数学问题,有多种解决方法。
下面我们介绍两种常见的方法。
递推公式递推公式是解决约瑟夫问题的一种简洁的方法。
假设有n个人参与,每次报到m的人被淘汰。
我们可以通过递推的方式计算出最后剩下的人在初始规模为n时的位置。
首先,我们用一个数组p来表示剩下的人的位置,初始时所有人都是存活的。
然后我们从第一个人开始报数,将每次报到m的人从数组中删除,并将其位置存储在另一个数组q中。
然后,继续从下一个人开始报数,重复这个过程,直到所有人都被删除。
最后,数组p中剩下的最后一个位置就是最后幸存的人。
def josephus(n, m):p = list(range(1, n+1))q = []index =0while len(p) >0:index = (index + m -1) % len(p)q.append(p.pop(index))return q[-1]这是一个用Python语言实现的递推公式方法的示例。
其中,n为初始人数,m 为每次报到的数目。
这个方法的时间复杂度为O(nm),可以在很短的时间内解决大规模的约瑟夫问题。
数学推导除了使用递推公式的方法外,我们还可以通过数学推导来解决约瑟夫问题。
假设有n个人参与,每次报到m的人被淘汰。
我们首先考虑特殊情况,即初始人数为2时的解法。
当初始人数为2时,只有两个人,我们不用进行报数,直接将第一个人淘汰,第二个人即是最后幸存的人。
当初始人数为3时,我们需要依次报到1、2、3,淘汰第3个人。
然后,剩下的两个人重新排成一个圆圈,继续从1开始报数,每次淘汰第3个人,直到只剩下一个人。
约瑟夫问题

第一个人出列:从 数器 j 从 1 数到 person[i] <- 0 第二个人出列:从 数器 j 从 1 数到 person[i] <- 0 „„ n-1个出列:„„
k = 0 的后继开始扫描数组,报数计 m,该人出列,把他的状态置成 0,
k = i 的后继开始扫描数组,报数计 m,该人出列,把他的状态置成 0,
此题如果意思是定位第 m 个元素,当不需要跳过任何元素 时。 从 k 开始报数第 m 个元素是: ((( k + m - 1 ) – 1 ) mod ) n +1
“遍历”和“数到”的区别: 遍历到的每个元素需要做相同的操作,而“数到m”第m个 元素和前 m-1 个元素有不同的操作。
如果需要跳过某些标记的元素,就无法直接确定第 m 个元 素的位置,则需要按顺序逐个扫描元素,跳过不符合要求的 元素,对符合要求的元素进行计数。 此处注意第一个数也许需要跳过,第一个报数的编号也许不 是 k,不能直接从 1 计数。 i <- k j <- 0 while ( j< m ) do begin i <- (i mod n) + 1 if ( person[i] <> 0 ) then j <- j+1 end
2.1
模拟方法
2.2
2.1.1 数组+标记 2.1.2 循环链表+删除节点
数学模型
定义数组: array person[1..n]代表 n 个人的状态; 第i个元素代表编号为i的人的状态,下标代表人的编号; 状态: 1代表没有出列,0代表已出列。 使用线性数组表示环状圆圈 * 数组元素间相邻关系和环状结构元素间相邻关系有所不 同,person[n]没有后继节点,person[1]没有前驱节点。 数组可以使用下面方法实现环状结构的相邻关系: person[i]后继节点的下标为j: if i = n then i<- 1 else i <- i+1 或者 i <- (i mod n) +1
约瑟夫环问题的两种解法(详解)

约瑟夫环问题的两种解法(详解)约瑟夫环问题的两种解法(详解)题⽬:Josephus有过的故事:39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓。
于是决定了⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀。
然后下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
然⽽Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。
对于这个题⽬⼤概两种解法:⼀、使⽤循环链表模拟全过程⼆、公式法我们假设这41个⼈编号是从0开始,从1开始报数,第3个⼈⾃杀。
1、最开始我们有这么多⼈:[ 0 1 2 3 4 5 ... 37 38 39 40 ]2、第⼀次⾃杀,则是(3-1)%41=2 这个⼈⾃杀,则剩下:[ 0 1 3 4 5 ... 37 38 39 40 ]3、然后就是从编号为3%41=3的⼈开始从1报数,那么3号就相当于头,既然是头为什么不把它置为0,这样从它开始就⼜是与第1,2步⼀样的步骤了,只是⼈数少了⼀个,这样不就是递归了就可以得到递归公式。
想法有了就开始做:4、把第2步中剩下的⼈编号减去3映射为:[ -3 -2 0 1 2 ... 34 35 36 37 ]5、出现负数了,这样不利于我们计算,既然是环形,37后⾯报数的应该是-3,-2,那么把他们加上⼀个总数(相当于加上360度,得到的还是它)[ 38 39 0 1 2 3 ... 34 35 36 37 ]6、这样就是⼀个总数为40个⼈,报数到3杀⼀个⼈的游戏。
这次⾃杀的是第5步中的(3-1)%40=2号,但是我们想要的是第2步中的编号(也就是最初的编号)那最初的是多少?对应回去是5;这个5是如何得到的呢?是(2+3)%41得到的。
⼤家可以把第5步中所有元素对应到第2步都是正确的。
7、接下来是[ 35 36 37 38 0 1 2... 31 32 33 34 ]⾃杀的是(3-1)%39=2,先对应到第5步中是(2+3)%40=5,对应到第2步是(5+3)%41=8。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
约瑟夫斯问题
问题描述
约瑟夫斯问题是一个经典的数学问题,也被称为约瑟夫环问题。
问题的描述如下:有n个人围成一圈,从第一个人开始报数,报到m的人出列,然后从出列的下一个人开始重新报数,再次报到m的人出列,如此循环,直到所有人都出列为止。
那么,最后剩下的人在原来的顺序中编号是几?
算法思路
为了解决约瑟夫斯问题,可以使用一种常用的数学技巧来计算最后剩下的人的编号。
假设n个人的编号分别为0, 1, 2, …, n-1,那么可以得到一个递推公式:
f(n, m) = (f(n-1, m) + m) % n
其中f(n, m)表示有n个人时最后剩下的人的编号。
根据这个递推公式,可以进行递归计算。
算法实现
下面是使用Python语言实现约瑟夫斯问题的算法:
```python def josephus(n, m): if n == 1: return 0 else: return (josephus(n-1, m) + m) % n
测试样例
n = 7 # 总人数 m = 3 # 报数到m时出列 survivor = josephus(n, m) print(。