约瑟夫问题与因式分解
C语言经典算法大全
C语言经典算法大全➢老掉牙河内塔费式数列巴斯卡三角形三色棋老鼠走迷官(一)老鼠走迷官(二)骑士走棋盘八个皇后八枚银币生命游戏字串核对双色、三色河内塔背包问题(Knapsack Problem)➢数、运算蒙地卡罗法求PIEratosthenes筛选求质数超长整数运算(大数运算)长PI最大公因数、最小公倍数、因式分解完美数阿姆斯壮数最大访客数中序式转后序式(前序式)后序式的运算➢关于赌博洗扑克牌(乱数排列)Craps赌博游戏约瑟夫问题(Josephus Problem)➢集合问题排列组合格雷码(Gray Code)产生可能的集合m元素集合的n个元素子集数字拆解➢排序得分排行选择、插入、气泡排序Shell 排序法—改良的插入排序Shaker 排序法- 改良的气泡排序Heap 排序法—改良的选择排序快速排序法(一)快速排序法(二)快速排序法(三)合并排序法基数排序法➢搜寻循序搜寻法(使用卫兵)二分搜寻法(搜寻原则的代表) 插补搜寻法费氏搜寻法➢矩阵稀疏矩阵多维矩阵转一维矩阵上三角、下三角、对称矩阵奇数魔方阵4N 魔方阵2(2N+1) 魔方阵1.河内之塔说明河内之塔(Towers of Hanoi)是法国人M。
Claus(Lucas)于1883年从泰国带至法国的,河内为越战时北越的首都,即现在的胡志明市;1883年法国数学家Edouard Lucas曾提及这个故事,据说创世纪时Benares有一座波罗教塔,是由三支钻石棒(Pag)所支撑,开始时神在第一根棒上放置64个由上至下依由小至大排列的金盘(Disc),并命令僧侣将所有的金盘从第一根石棒移至第三根石棒,且搬运过程中遵守大盘子在小盘子之下的原则,若每日仅搬一个盘子,则当盘子全数搬运完毕之时,此塔将毁损,而也就是世界末日来临之时.解法如果柱子标为ABC,要由A搬至C,在只有一个盘子时,就将它直接搬至C,当有两个盘子,就将B当作辅助柱。
如果盘数超过2个,将第三个以下的盘子遮起来,就很简单了,每次处理两个盘子,也就是:A->B、A -〉C、B—>C这三个步骤,而被遮住的部份,其实就是进入程式的递回处理。
抽杀问题 约瑟夫问题
[阅读材料]世界名题与小升初之:抽杀问题(約瑟夫问题)--马到成功老师在各类竞赛中,各类小升初考试中相关的世界名题出现的概率极高,这是由小升初与数学竞赛的特点决定,这特点便是:知识性,趣味性,思想性相结合。
先给大家介绍这一问题的由来。
据说著名犹太历史学家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个位置,之前的人都死光了,所以他们也就不知道約瑟夫与他的朋友并没有遵守游戏规则了。
约 瑟 夫 环 问 题 的 三 种 解 法
约瑟夫环问题的简单解法(数学公式法)关于约瑟夫环问题,无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。
我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。
因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。
求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始): k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。
现在我们把他们的编号做一下转换:k-2 – n-2k-1 – n-1解x’ —- 解为x注意x’就是最终的解变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x’=(x+k)%n如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。
(n-2)个人的解呢?当然是先求(n-3)的情况—- 这显然就是一个倒推问题!下面举例说明:假设现在是6个人(编号从0到5)报数,报到(2-1)的退出,即 m=2。
那么第一次编号为1的人退出圈子,从他之后的人开始算起,序列变为2,3,4,5,0,即问题变成了这5个人报数的问题,将序号做一下转换:现在假设x为0,1,2,3,4的解,x’设为那么原问题的解(这里注意,2,3,4,5,0的解就是0,1,2,3,4,5的解,因为1出去了,结果还是一个),根据观察发现,x与x’关系为x’=(x+m)%n,因此只要求出x,就可以求x’。
具体数学笔记-约瑟夫问题
具体数学笔记-约瑟夫问题据说著名犹太历史学家Josephus有过以下的故事:在罗马⼈占领乔塔帕特后,39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓到,于是决定了⼀个⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
然⽽Josephus和他的朋友并不想遵从。
⾸先从⼀个⼈开始,越过k−2个⼈(因为第⼀个⼈已经被越过),并杀掉第k个⼈。
接着,再越过k−1个⼈,并杀掉第k个⼈。
这个过程沿着圆圈⼀直进⾏,直到最终只剩下⼀个⼈留下,这个⼈就可以继续活着。
问题是,给定了和,⼀开始要站在什么地⽅才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。
现在考虑k=2时的问题,我们设J(n)表⽰当有n个⼈时幸存者的编号。
假设⼀开始有2n个⼈,那么⼀轮后会剩下1,3,5,7...2n−1,并且⼜是从1开始跳。
所以J(2n)=2J(n)−1奇数的情况差不多,会剩下3,5,7,9....2n+1所以J(2n+1)=2J(n)+1⽤这个⽅法可以在log2n的时间内求出J(n)接下来我们可以打⼀个表容易发现J(2m+l)=2l+10≤l<2m⽤数学归纳法很容易证。
⾄此这个问题已经解决,但我们还可以发现⼀些东西。
设n的⼆进制展开为n=(b m b m−1...b1b0)2b m=1把2l+1表⽰出来2l+1=(b m−1...b1b01)2这就是n在⼆进制下向左循环移动了⼀位。
难道是碰巧吗?考虑这个递推式的⼀般形式f(1)=af(2n)=2f(n)+bf(2n+1)=2f(n)+ca,b,c显然是互不影响的,f(n)⼀定可以这样表⽰出来f(n)=A(n)a+B(n)b+C(n)c可以看出对于所有的a,b,c,A,B,C都是相同的我们取a=1,b=c=0f(n)=A(n)A(1)=1A(2n)=2A(n)A(2n+1)=2A(n)则A(2m+l)=2m接下来我们反过来使⽤递推式,确定f(n),研究是否有a,b,c能表⽰它,取f(n)=1解得a,b,c=(1,−1,−1)−−−−−>A(n)−B(n)−C(n)=f(n)=1再取f(n)=n就可以解出A,B,C了。
最新小学数学故事:约瑟夫问题与因式分解
最新小学数学故事:约瑟夫问题与因式分解我国古代的读书人,从上学之日起,就日诵不辍,一般在几年内就能识记几千个汉字,熟记几百篇文章,写出的诗文也是字斟句酌,琅琅上口,成为满腹经纶的文人。
为什么在现代化教学的今天,我们念了十几年书的高中毕业生甚至大学生,竟提起作文就头疼,写不出像样的文章呢?吕叔湘先生早在1978年就尖锐地提出:“中小学语文教学效果差,中学语文毕业生语文水平低,……十几年上课总时数是9160课时,语文是2749课时,恰好是30%,十年的时间,二千七百多课时,用来学本国语文,却是大多数不过关,岂非咄咄怪事!”寻根究底,其主要原因就是腹中无物。
特别是写议论文,初中水平以上的学生都知道议论文的“三要素”是论点、论据、论证,也通晓议论文的基本结构:提出问题――分析问题――解决问题,但真正动起笔来就犯难了。
知道“是这样”,就是讲不出“为什么”。
根本原因还是无“米”下“锅”。
于是便翻开作文集锦之类的书大段抄起来,抄人家的名言警句,抄人家的事例,不参考作文书就很难写出像样的文章。
所以,词汇贫乏、内容空洞、千篇一律便成了中学生作文的通病。
要解决这个问题,不能单在布局谋篇等写作技方面下功夫,必须认识到“死记硬背”的重要性,让学生积累足够的“米”。
为帮助大家提高学习数学是兴趣,查字典数学网为同学们特别提供了约瑟夫问题与因式分解,希望对大家的学习有所帮助!生活中出处充满数学的趣味,在这里济南奥数网小编为大家整理了一些小学生数学故事,希望济南的家长和孩子能在快乐中了解数学,爱上数学。
小学生数学故事:约瑟夫问题与因式分解有一个古老的传说,有64名战士被敌人俘虏了,敌人命令它们排成一个圈,编上号码1,2,3,……64。
敌人把1号杀了,又把3号杀了,他们是隔一个杀一个这样转着圈杀。
最后剩下一个人,这个人就是约瑟夫,请问约瑟夫是多少号? 宋以后,京师所设小学馆和武学堂中的教师称谓皆称之为“教谕”。
至元明清之县学一律循之不变。
约 瑟 夫 环 问 题 的 三 种 解 法
约瑟夫环问题的简单解法(数学公式法)关于约瑟夫环问题,无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。
我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。
因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。
求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。
现在我们把他们的编号做一下转换:k-2 – n-2k-1 – n-1解x’ —- 解为x注意x’就是最终的解变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x’=(x+k)%n如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。
(n-2)个人的解呢?当然是先求(n-3)的情况—- 这显然就是一个倒推问题!下面举例说明:假设现在是6个人(编号从0到5)报数,报到(2-1)的退出,即 m=2。
那么第一次编号为1的人退出圈子,从他之后的人开始算起,序列变为2,3,4,5,0,即问题变成了这5个人报数的问题,将序号做一下转换:现在假设x为0,1,2,3,4的解,x’设为那么原问题的解(这里注意,2,3,4,5,0的解就是0,1,2,3,4,5的解,因为1出去了,结果还是一个),根据观察发现,x与x’关系为x’=(x+m)%n,因此只要求出x,就可以求x’。
约瑟夫问题
第一个人出列:从 数器 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
约瑟夫斯问题
约瑟夫斯问题约瑟夫问题维基百科,⾃由的百科全书跳到导航跳到搜索约瑟夫问题(有时也称为约瑟夫斯置换),是⼀个出现在计算机科学和数学中的问题。
在计算机编程的算法中,类似问题⼜称为约瑟夫环。
⼈们站在⼀个等待被处决的圈⼦⾥。
计数从圆圈中的指定点开始,并沿指定⽅向围绕圆圈进⾏。
在跳过指定数量的⼈之后,处刑下⼀个⼈。
对剩下的⼈重复该过程,从下⼀个⼈开始,朝同⼀⽅向跳过相同数量的⼈,直到只剩下⼀个⼈,并被释放。
问题即,给定⼈数、起点、⽅向和要跳过的数字,选择初始圆圈中的位置以避免被处决。
历史这个问题是以弗拉维奥·约瑟夫命名的,他是1世纪的⼀名犹太历史学家。
他在⾃⼰的⽇记中写道,他和他的40个战友被罗马军队包围在洞中。
他们讨论是⾃杀还是被俘,最终决定⾃杀,并以抽签的⽅式决定谁杀掉谁。
约瑟夫斯和另外⼀个⼈是最后两个留下的⼈。
约瑟夫斯说服了那个⼈,他们将向罗马军队投降,不再⾃杀。
约瑟夫斯把他的存活归因于运⽓或天意,他不知道是哪⼀个。
[1]解法⽐较简单的做法是⽤循环单链表模拟整个过程,时间复杂度是O(n*m)。
如果只是想求得最后剩下的⼈,则可以⽤数学推导的⽅式得出公式。
且先看看模拟过程的解法。
Python版本-- coding: utf-8 --class Node(object):def init(self, value):self.value = valueself.next = Nonedef create_linkList(n):head = Node(1)pre = headfor i in range(2, n+1):newNode = Node(i)pre.next= newNodepre = newNodepre.next = headreturn headn = 5 #总的个数m = 2 #数的数⽬if m == 1: #如果是1的话,特殊处理,直接输出print (n)else:head = create_linkList(n)pre = Nonecur = headwhile cur.next != cur: #终⽌条件是节点的下⼀个节点指向本⾝for i in range(m-1):pre = curcur = cur.nextprint (cur.value)pre.next = cur.nextcur.next = Nonecur = pre.nextprint (cur.value)using namespace std;typedef struct _LinkNode {int value;struct _LinkNode* next;} LinkNode, *LinkNodePtr;LinkNodePtr createCycle(int total) {int index = 1;LinkNodePtr head = NULL, curr = NULL, prev = NULL;head = (LinkNodePtr) malloc(sizeof(LinkNode));head->value = index;prev = head;while (--total > 0) {curr = (LinkNodePtr) malloc(sizeof(LinkNode));curr->value = ++index;prev->next = curr;prev = curr;}curr->next = head;return head;}void run(int total, int tag) {LinkNodePtr node = createCycle(total);LinkNodePtr prev = NULL;int start = 1;int index = start;while (node && node->next) {if (index == tag) {printf("%d\n", node->value);prev = node->next;node->next = NULL;node = prev;} else {prev->next = node->next;node->next = NULL;node = prev->next;}index = start;} else {prev = node;node = node->next;index++;}}}int main() {if (argc < 3) return -1;run(atoi(argv[1]), atoi(argv[2]));return 0;}数学推导解法我们将明确解出{\displaystyle k=2}k=2时的问题。
约瑟夫问题多种解决方法
著名约瑟夫问题一
• 17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了 这样一个故事:15个教徒和15 个非教徒在深海上遇险, 必须将一半的人投入海中,其余的人才能幸免于难,于是 想了一个办法:30个人围成一圆圈,从第一个人开始依次 报数,每数到第九个人就将他扔入大海,如此循环进行直 到仅余15个人为止。问怎样排法,才能使每次投入大海的 都是非教徒。题目中30个人围成一圈,因而启发我们用一 个循环的链来表示。可以使用结构数组来构成一个循环链。 结构中有两个成员,其一为指向下一个人的指针,以构成 环形的链;其二为该人是否被扔下海的标记,为1表示还 在船上。从第一个人开始对还未扔下海的人进行计数,每 数到9时,将结构中的标记改为0,表示该人已被扔下海了。 这样循环计数直到有15个人被扔下海为止
约瑟夫问题的另外一个有名的例子
• 一堆猴子都有编号,编号是1,2,3 ...m , 这群猴子(m个)按照1-m的顺序围坐一圈, 从第1开始数,每数到第N个,该猴子就要 离开此圈,这样依次下来,直到圈中只剩 下最后一只猴子,则该猴子为大王。
• 二. 基本要求: (1) 输入数据:输入 m,n m,n 为整数,n<m (2)中文提示 按照m个猴子,数n 个数的方法,输出为大 王的猴子是几号 ,建立一个函数来实现此 功能
12
• p2->next=p1; • p2=p1; •} • p2->next=head; • return head; •} • struct monkey *findout(struct monkey *start,int
n) •{ • int i; • struct monkey *p; • i=n; • p=start;
• cout<<"----------------------------------------
约瑟夫问题的解法及引发的整数进制问题思考
约瑟夫问题的解法及引发的整数进制问题思考【摘要】:约瑟夫(Josephus)问题(也称约瑟夫斯置换,约瑟夫环问题),是一个出现在计算机科学和数学中的经典问题. 本文将就约瑟夫问题的算法复杂度优化、纯数学解法和引申出的数论进制问题进行讨论和创新,后两部分为本文研讨的重点,即离散数学中数论方面的进制问题.【关键词】:约瑟夫(Josephus)问题,算法优化与纯数学,整数p进制及其应用.首先让我们来回顾一下经典约瑟夫问题的表述:著名犹太历史学家约瑟夫有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人宁死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止. 约瑟夫将朋友与自己安排在第16个与第31个位置,逃过了这场死亡游戏.将其抽象为一般数学问题(抽杀问题)则为:N(n)个人围成一圈,从第一个开始报数,第M(m)个将被杀掉,直至留下最后一个,求剩下的最后一个在原排列中的数码.由其派生的一系列抽杀问题、猴子选王问题在本文不做讨论,重点在于引申的进制问题.1.算法模拟及其复杂度优化1.1正常模拟——复杂度()o nm题目中N个人围成一圈,因而启发我们用一个循环的链来表示. 可以使用结构数组来构成一个循环链. 结构中有两个成员,一个为指向下一个人的指针,以构成环形的链;另一个为该人是否自杀的标记,1表示未被杀. 从第一个人开始对未自杀的人进行计数,每数到9时,将结构中的标记改为0,表示该人已自杀. 这样循环计数直到剩下最后一个.基于程序设计课试写了一段源代码,这次对其无用部分做了缩减和修改(复杂度o(nm)):#include<iostream>using namespace std;void main(){int n, m, a[10001], k, i, j, num;cout << "n = ";cin >> n;if (n>10000){cout << "Beyond!" << endl;return;}cout << "m = ";cin >> m;for (i = 1; i <= n; i++){a[i] = 1;}j = 0;k = 0;for (i = 1; i <= n + 1; i++){if (a[i] == 1) { j = j + a[i]; if (j == m) { j = 0; a[i] = 0; k++;}if (k == n) { num = i; break ; }}if (i == n + 1)i = 0; }cout << "number " << num << " wins " << endl;}1.2一级优化——复杂度()o n对于链表或是数组的模拟形态,在数据较大的N 中我们发现程序的运行大大受制于其复杂度,又考虑到实际上不需要对原题所述的情况进行赋值,故而可以打破常规,先对于原题进行以下的数学分析,再编写一个运行相对快捷的代码.运用数学归纳法的思想,在第一个人mod(n 1)m -出列之后,剩下的1n -个人组成了一个新的约瑟夫环(从mod(n 1)k m =-编号开始),继而我们对新组的编号做一下平移:112211k k k n k n →+→-→--→-对新组的'()mod(n)x x k =+如此一来,我们得到了前后关系的连接媒介,可以根据初值写出如下的关键式:(1)0f =()()mod ,1f f m i i =+>有了这个公式,我们只需要从1n →顺序递推出值,得出[]f n . 由于题目中编号总是从1开始,输出[]1f n +即可. 代码如下(C 语言):#include <stdio.h>int main() { int n, m, i, s = 0;printf("n m = "); scanf("%d%d", &n, &m); for (i = 2; i <= n; i++) s = (s + m) % i; printf("number %d wins\n", s + 1);}1.3二级优化(来自网络文献)——复杂度()o m进一步,如果我们观察删去和最终留下的号码,我们会发现它常常处在一种等差的状态n (m=3) 剩余号s16832 4 1 1 17 11 33 7 2 2 18 14 34 10 3 2 19 17 35 13 4 1 20 20 36 16 5 4 21 2 37 19 6 1 22 5 38 22 7 4 23 8 39 25 8 7 24 11 40 28 9 1 25 14 41 31 10 4 26 17 42 34 11 7 27 20 43 37 12 10 28 23 44 40 13 13 29 26 45 43 14 2 30 29 46 46 15 531 147 2观察1.2中的变量s :()%s s m i =+,可以看出,当i 比较大而1s m +-比较小的时候,s 就处于一种等差递增的状态,这个等差递增的过程可以跳过.我们设一中间变量x ,列出如下等式:–1s m x i x +⨯=+解出x ,令s s m x =+⨯,将i x +直接赋值给i ,这样就跳过了中间共x 重的循环,从而节省了等差递增的时间开销. 当求出来的i x +超过n 时,我们便可以结束循环了. 这个方法跳脱出了n 的束缚,复杂度进一步缩减到了(m)o . 以下的代码来自于一篇博文,由于该部分不是本文讨论的重点,没有进行实践:long Josephus(long n,long m,long k) //分别为:人数,出圈步长,起使报数位置, {if (m == 1)k = k == 1 ? n : (k + n - 1) % n; else {for (long i = 1; i <= n; i++) {if ((k + m) < i) {x = (i - k + 1) / (m - 1) - 1; if (i + x < n) {i = i + x;k = (k + m * x); } else {k = k + m * (n - i) ; i = n; } }k = (k + m - 1) % i + 1; } }return k; //返回最后一人的位置}2. 纯数学解答中的归纳与发现2.1对2m =情况的解答想要从纯数学的角度来解答这样一个复杂问题,首先需要从2m =的特殊情况来探讨一些规律和特殊情况.n (m=2) 剩余号s17327 23 8 1 18 5 28 25 9 3 19 7 29 27 10 5 20 9 30 29 11 7 21 11 31 31 12 9 22 13 32 1 13 11 23 15 33 3 14 13 24 17 34 5 15 15 25 19 35 7 16 1262136 9从上表中我们可以发现对于2(k )k ∈ ,始终有1s =,故而易想到将其作为归纳之基,可以得出如下的一种归纳证法:① 2in =时,易得每一次删减处理的数分别为2k ,221k - ,323k -,……,2(23)ik i -- 第s圈删去2i s-个数,最终剩下的是k ∀∈ ,k i ≤,mod(2)k均为1的第一号数码.② 2,(121)i in j j =+≤≤-时,先抽杀j 个数码,接下来剩下的2i个数码是以21j +开头(相当于数码1)的新环列,运用①中的相关结论可得,最终剩下存活的恰是21j +号数码的人. 由①②可以归总得2m =的一般数学解:满足2,(021)i in j j =+≤≤-的约瑟夫环列,最终剩下的数码是21j +这道题的解答是否就这样完成了呢?在进行测算的过程中,我们其实能发现,找出使得2i最接近n 的数字i 是一大关键点. 而恰好在进制转化的过程中,这一问题被交代成了对应二进制数的第一位数问题,故而我将n m 、分别进行了二进制转化,并发现了一定规律:n (10)s (2)n (2)s (2)(2)n s - 8 1 1000 0001 111 9 3 1001 0011 110 10 5 1010 0101 101 11 7 1011 0111 100 12 9 1100 1001 11 13 11 1101 1011 10 14 13 1110 1101 1 15 15 1111 1111 0 161 10000 00001 1111注:(2)n 表示n 的二进制数码,其余类比.就如上述表格中所显示的一样,在二进制数码中,出现了惊人的对称与平移现象,在每一个(2)n 与(2)s 中最“外部”的1保持轴对称,其余数码直接平移就可以完成. 基于其形状可将其命名为“进制平移外称塔”. 仔细想来,二进制数码的第一位即象征十进制解法中的2i,21j +对二进制而言既是末尾加1,整体动作看起来就像将第一位数字移到了末位.有这样的解法的启发,我们是不是能够对任意m 来探讨m 进制下的数码变换而得到更加有新意且简便的解法呢?2.2对3m =情况的讨论基于2.1中的发现,我对3m =的情况进行了进一步的列举和研究,如下表:n (10)s (3)n (3)s16 8 121 02232 4 1012 0011 1 1 1 1 17 11 122 102 33 7 1020 0021 2 2 2 2 18 14 200 112 34 10 1021 0101 3 2 10 02 19 17 201 122 35 13 1022 0111 4 1 11 01 20 20 202 202 36 16 1100 0121 5 4 12 11 21 2 210 002 37 19 1101 0201 6 1 20 01 22 5 211 012 38 22 1102 0211 7 4 21 11 23 8 212 022 39 25 1110 0221 8 7 22 21 24 11 220 102 40 28 1111 1001 9 1 100 001 25 14 221 112 41 31 1112 1011 10 4 101 011 26 17 222 122 42 34 1120 1021 11 7 102 021 27 20 1000 0202 43 37 1121 1101 12 10 110 101 28 23 1001 0212 44 40 1122 1111 13 13 111 111 29 26 1002 0222 45 43 1200 1121 14 2 112 002 30 29 1010 1002 46 46 1201 1201 155 120 01231 1 1011 000147 2 1202 0002很遗憾,并没有出现如二进制表中一样令人兴奋的现象,经过反复比对和解答,最终得到的规律与代码算法中1.2或是1.3的简化也是异曲同工,其解法最终也归结于批量倒推(详见百度百科词条“约瑟夫问题”中最后一部分),并没有想象中的独特结论.2.3对3m =情况的变题对于2.2尝试的失败,是否意味着之前的进制论不具有实际的意义?我认为答案是否定的. 对此,我再次回顾了题目的描述,并将原题中的留1,2抽杀3改为留1抽杀2,3. 对这一变题在3进制的情况下进行进一步探究,发现了如下表格中所示的规律:n '(10)s (3)n '(3)s (3)s'(3)n -1 1 1 1 0 3 1 10 012 5 4 12 11 1 7 7 14 21 0 9 1 100 001 22 11 4 102 011 21 13 7 111 021 20 15 10 120 101 12 17 13 122 111 11 19 16 124 121 10 21 19 140 201 2 23 22 142 211 1 25 25 144 221 0 27 1 1000 0001 222 29 4 1002 0011 221 31 7 1011 0021 220 33 10 1020 0101 212 35 13 1022 0111 211 37 16 1101 0121 210 39 19 1110 0201 202 41 22 1112 0211 201 43 25 1121 0221 200 45 28 1200 1001 122 4731 1202 1011 121注:为了方便辨识,原本在三进制中没有的数字4在此被用来(不进位留下的数码)进行(3)n 与'(3)s 的比对.在这张表格中我们可以轻易发现同样存在着首位数码减去的1移至末位,并有中间数码平移的情况,与前面不同的是,这次的平移是缩倍平移,首位减1后的数码被除2之后成为了'(3)s 中的前数位. “进制平移外称塔”的规律依然存在. 在证明这一部分的时候我发现,其证明方式与2.1中递推证明2m =的方法方式并无不同,在此就不多作赘述.那么这样一个看起来“漂亮”的结论有什么实际意义呢?实际上,在编程题中来自于定义整型或数组的限制,使得n 具有一定的上限,而在这个方法中我们依靠在线进制转换器和电脑自带的计算器,可以对极大的数码进行运算如123456707654321:(10(3))121012010100100020001123456707622222020521243=(3)(3)21012010100100020001222220202210121001200011121112111110101÷=(3)(10)10121001200011121112111110101182239495434158=其中第二部三进制除法若不熟悉进制除法也可转化为十进制计算,本方法需要如下两个必备条件:进制转化器与科学型计算器.3.引申的整数进制问题的探讨经过了上面的讨论,我们已经对进制法在解决一些实际问题中的应用有了初步的认识,而事实上,进制法在多重削减类问题、整除问题、立方体积问题以及密码问题有大量的运用,版面有限,下述我们将只就其中的几个方面的例题进行分析,加深对进制法解题的印象.3.1在多重削减类问题中的应用其实约瑟夫问题,可以看作是一种多重循环的削减,直至削减到所需的数值为止,故而在这一类题目中,往往根据削减的层级p,整数的p进制有强大的效力,例如称重问题,是反复出现在小、初、高竞赛题中变化不竭的问题之一. 我为以上的这类或与之相似的题目一并命名为“多重削减类问题”,佐证此,特意寻找了记忆犹新的一道来自奥赛经典书本上的题(图片来自网络的扫描版):3.2在整除问题中的应用由于p 进制的独特表述和适应性的计算法则,在整除问题中整数的p 进制通常有很好的实际效用,在接下来的两道题中我将展示第一道题的解答,另一题由于时间紧迫而没有能够解出答案,望老师谅解……例2.1:(2005年中国奥林匹克协作体夏令营试题)如果一个正整数n 在三进制下表示的各数字之和可以被3整除,那么我们称n 为“好的”,则前2005个“好的”正整数之和是多少?解:首先考虑“好的”非负整数,考察如下两个引理:引理1:在3个连续非负整数3,31,32n n n ++(n 是非负整数)中,有且仅有1个是“好的”.证明:在这三个非负整数的三进制表示中,0,1,2各在最后一位出现一次,其作各位数字相同,于是三个数各位数字之和是三个连续的正整数,其中有且仅有一个能被3整除(即“好的”),引理1得证.引理2:在9个连续非负整数9,91,98n n n ++ (n 是非负整数)中,有且仅有3个是“好的”. 把这3个“好的”非负整数化成三进制,0,1,2恰好在这三个三进制数的最后一位各出现一次.证明:由引理1不难得知在9个连续非负整数9,91,98n n n ++ (n 是非负整数)中,有且仅有3个是“好的”.另一方面,在这三个“好的”非负整数的三进制表示中,最高位与倒数第三位完全相同,倒数第二位分别取0,1,2. 若它使它们成为“好的”非负整数,则最后一位不相同,引理2得证.将所有“好的”非负整数按从小到大的顺序排成一列,设第2004个“好的”非负整数为m ,根据引理1,得2003320043m ⨯≤<⨯,即60096012m ≤<.设前m 个“好的”正整数之和为m S ,由于前2003个“好的”正整数之和等于前2004个“好的”非负整数之和. 因此:2003(0122003)320046023022S =+++⨯+= 又因为103(6013)(22020201)=和103(6015)(22020210)=都是“好的”正整数. 因此前2005年“好的”正整数之和是:20052003601360156035050S S =++=例2.2:(2005年国家队数学培训题)互素正整数n p ,n q 满足1111,23n n p q n=+++ 试找出所有的正整数n ,使得3n p .注:也希望老师给这一道题一些点拨和建议.3.3在其他问题中的应用除了上述的典型问题之外,整数p 进制在很多方面仍然有着应用,在此不多作阐述,仅举一例,这一例来自于高中期间我组织全校知识风尚大赛时为高一年级原创的一道笔试思考题(较为简单):例3.1【原创】现甲乙都有一本海门年鉴共1012页(包含绝大多数常用字),一页至多15段,每段至多31行,每行至多31字,而乙的电脑损坏只能识别7或以下的数字. 求设计一种八位密码方式,使两人能正常交流而不持有揭秘方式和密码本年鉴的人不能破译. (4’)(答案也许不唯一,欢迎同学们提供其他方案)解:考虑到1012接近1024,15、31又明显提示进行二进制转化。
约瑟夫环的数学推导
约瑟夫环—公式法约瑟夫问题是个著名的问题,N 个人围成一圈,第一个人从1开始报数,报M 的将被杀掉,下一个人接着从1开始报。
如此反复,最后剩下一个,求最后的胜利者的编号。
约瑟夫环是一个经典的数学问题,我们不难发现这样的依次报数是有规律可循的。
为了方便导出递推公式,我们重新定义一下题目。
问题:N 个人编号为1,2,……,N ,依次报数,报到M 时杀掉那个人,下一个人从1开始报,求最后胜利者的编号。
先给出公式:(,)((1,))%f N M f N M M N =-+,其中(,)f N M 表示N 个人报数,报到M 的人被杀掉,最后胜利者的编号;(1,)f N M -表示N-1个人报数,报到M 的人被杀掉,最后胜利者的编号。
下面我们用数字来演示一下这个过程,其中N=11,M=3。
将上面表格的每一行看成数组,这个公式描述的是:胜利者在这一轮的下标位置。
(1,3)f :下标位置为0;(2,3)f :下标位置为1;(3,3)f :下标位置为1; (4,3)f :下标位置为0;(5,3)f :下标位置为3;…… ……(11,3)f :下标位置为6。
满足(,)((1,))%f N M f N M M N =-+。
下面回答三个小问题:问题1: 假设我们已经知道11个人时,胜利者的下标位置为6。
那下一轮10个人时,胜利者的下标位置为多少?答: 其实吧,第一轮删掉编号为3的人后,之后的人都往前面移动了3位,胜利这也往前移动了3位,所以他的下标位置由6变成3。
问题2: 假设我们已经知道10个人时,胜利者的下标位置为3。
那下一轮11个人时,胜利者的下标位置为多少?答: 这可以看成上一个问题的逆过程,大家都往后移动3位,所以(11,3)(10,3)3f f =+。
不过有可能数组会越界,所以最后需要模上当前人数的个数,即(11,3)((10,3)3)%11f f =+。
问题3: 现在改为人数改为N ,报到M 时,把那个人杀掉,那么数组是怎么移动的? 答: 每杀掉一个人,下一个人成为头,相当于把数组向前移动M 位。
约瑟夫环问题(最简单的数学解法)
约瑟夫环问题(最简单的数学解法)基本问题描述:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。
从编号为1的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,直到圆桌周围的⼈全部出列。
(也类似于变态杀⼈狂问题)通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。
通常,我们会要求输出最后⼀位出列的⼈的序号。
那么这⾥主要研究的是最后⼀个出列的⼈的序号要怎么确定。
当n,m数据量很⼩的时候,我们可以⽤循环链表模拟约瑟夫环的过程。
当模拟到⼈数等于1的时候,输出剩下的⼈的序号即可。
这种⽅法往往实现起来⽐较简单,⽽且也很容易理解。
但是时间复杂度却是很糟糕的,达到了O(n m),这样的话,其实在n,m⽐较⼤的时候(n m达到10^8或者更⼤),那么要得出结果往往需要耗费很长的时间,但是我们可以运⽤⼀点数学上的技巧,将最后结果推导出来。
为了简化出列的过程:⾸先我们把这n个⼈的序号编号从0~n-1(理由很简单,由于m是可能⼤于n的,⽽当m⼤于等于n时,那么第⼀个出列的⼈编号是m%n,⽽m%n是可能等于0的,这样编号的话能够简化后续出列的过程),当数到m-1的那个⼈出列,因此我们编号完成之后,开始分析出列的过程:第⼀次出列:⼀开始的时候,所有⼈的编号排成序列的模式即为:0,1,2,3,4,5...n-2,n-1那么第⼀次出列的⼈的编号则是(m-1)%n1,那么在第⼀个⼈出列之后,从他的下⼀个⼈⼜开始从0开始报数,为了⽅便我们设k1 =m%n1(n1为当前序列的总⼈数)那么在第⼀个⼈出列之后,k1则是下⼀次新的编号序列的⾸位元素,那么我们得到的新的编号序列为:k1,k1+1,k1+2,k1+3...n-2,n-1,0,1,2...k1-3,k1-2 (k1-1第⼀次已出列)那么在这个新的序列中,第⼀个⼈依旧是从0开始报数,那么在这个新的序列中,每个⼈报的相应数字为:0,1,2,3....n-2那么第⼆次每个⼈报的相应数字与第⼀次时⾃⼰相应的编号对应起来的关系则为:0 --> k11 --> k1+12 --> k1+2...n-2 ---> (k1+n-2)%n1(n1为当前序列的总⼈数,因为是循环的序列,k1+n-1可能⼤于总⼈数)那么这时我们要解决的问题就是n-1个⼈的报数问题(即n-1阶约瑟夫环的问题)可能以上过程你还是觉得不太清晰,那么我们重复以上过程,继续推导剩余的n-1个⼈的约瑟夫环的问题:那么在这剩下的n-1个⼈中,我们也可以为了⽅便,将这n-1个⼈编号为:0,1,2,3,4...n-2那么此时出列的⼈的编号则是(m-1) % n2(n2为当前序列的总⼈数),同样的我们设k2 = m % n2,那么在这个⼈出列了以后,序列重排,重排后新的编号序列为:k2,k2+1,k2+2,k2+3...n-2,n-1,0,1,2...k2-3,k2-2 (k2-1第⼀次已出列)那么在这个新的序列中,第⼀个⼈依旧是从1开始报数,那么在这个新的序列中,每个⼈报的相应数字为:1,2,3,4....n-2那么这样的话是不是⼜把问题转化成了n-2阶约瑟夫环的问题呢?后⾯的过程与前两次的过程⼀模⼀样,那么递归处理下去,直到最后只剩下⼀个⼈的时候,便可以直接得出结果当我们得到⼀个⼈的时候(即⼀阶约瑟夫环问题)的结果,那么我们是否能通过⼀阶约瑟夫环问题的结果,推导出⼆阶约瑟夫环的结果呢?借助上⾯的分析过程,我们知道,当在解决n阶约瑟夫环问题时,序号为k1的⼈出列后,剩下的n-1个⼈⼜重新组成了⼀个n-1阶的约瑟夫环,那么假如得到了这个n-1阶约瑟夫环问题的结果为ans(即最后⼀个出列的⼈编号为ans),那么我们通过上述分析过程,可以知道,n阶约瑟夫环的结果(ans + k)%n(n为当前序列的总⼈数),⽽k = m%n则有:n阶约瑟夫环的结果(ans + m % n)%n,那么我们还可以将该式进⾏⼀下简单的化简:当m<n时,易得上式可化简为:(ans + m)% n⽽当m>=n时,那么上式则化简为:(ans % n + m%n%n)% n即为:(ans % n + m%n)% n⽽(ans + m)% n = (ans % n + m%n)% n因此得证(ans + m % n)%n = (ans + m)% n这样的话,我们就得到了递推公式,由于编号是从0开始的,那么我们可以令f[1] = 0; //当⼀个⼈的时候,出队⼈员编号为0f[n] = (f[n-1] + m)%n //m表⽰每次数到该数的⼈出列,n表⽰当前序列的总⼈数⽽我们只需要得到第n次出列的结果即可,那么不需要另外声明数组保存数据,只需要直接⼀个for循环求得n阶约瑟夫环问题的结果即可由于往往现实⽣活中编号是从1-n,那么我们把最后的结果加1即可。
同游数学
巧查脚印破命案巴黎郊外有一座中世纪留下的古老城堡,其年代几乎与著名的“巴黎圣母院”同样久远,因而成了旅游观光的胜地,吸引了来自世界各地的游客。
下面这则故事就是出自—位导游之口。
古堡的顶层有一座尘封的钟楼,里面住着一个怪人,唯一的对外通道是个走起来嘎嘎响、陡峭异常的木质楼梯,大约有几十级,但肯定不到一百级。
某日黄昏,怪人的四位互不相识的朋友阿列克赛、巴顿、克林、杜邦,几乎在同一时间先后来访。
他们发现怪人已经被人杀害了,房间里面看起来很恐怖。
当下四人大惊失色,争先恐后地拼命逃走。
从脏乱不堪的狭窄楼梯(一次只能通过一人)跑下来,阿列克赛一步下2级台阶,巴顿一步下3级台阶,克林一步下4级台阶,而杜邦的本事最大,竟然一步能下5级台阶。
出事以后,侠盗亚森罗宾乔装成一名体面的上流社会绅士,自告奋勇地前来侦破此案。
他发现,同时印下四个人脚印的台阶仅在最高处和最低处。
为了追查凶手,脚印混乱了就不好办,于是亚森罗宾特别重视只留有一个人脚印的台阶。
后来的结果充分证明他的看法是正确无误的,最后终于抓获凶手,把他绳之以法。
现在要问你的是,通向钟楼的木楼梯上有多少级台阶只印下了一个人(不管是谁的)的脚印?(答案)由于4的倍数肯定是2的倍数,所以克林的情况可以不必考虑,这就省掉了一个人,2,3,4,5的最小公倍数是60,而60又小于100,所以钟楼的木楼梯共有60级台阶。
阿列克赛的脚印落在第2,4,6,8,l0,12,…,58,60级台阶上,但应排除2×3及其倍数的各级阶梯;同理,还需要排除4的倍数的各级阶梯和5的倍数的各级阶梯。
于是剩下第2,14,22,26,34,38,46,58共八级。
其一般形式为2×p(其中p=1,以及除去2、3、5以外的素数)。
巴顿的脚印落在第3,6,9,12,…,60级阶梯上,但应排除混有别人脚印的第6,12,15,18,……级阶梯,剩下第3,9,2l,27,33,39,51,57,共八级。
josephus环公式法
int N = Integer.parseInt(args[0]);
int M = Integer.parseInt(args[1]);
Node t = new Node(1);
Node x = t;
for (int i = 2; i <= N; x = (x.next=new Node(i++)));
f[i]=(f[i-1]+m)%i; (i>1)
有了这个公 式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1
由于是 逐级递推,不需要保存每个f[i],程序也是异常简单:
#i nclude <stdio.h>
maபைடு நூலகம்n()
如何知道 (n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是 f[n]
递推公式
f[1]=0;
}
无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几 乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施 一点数学策略。
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2
约瑟夫斯问题
约瑟夫斯问题
问题描述
约瑟夫斯问题是一个经典的数学问题,也被称为约瑟夫环问题。
问题的描述如下:有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(。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
有一个古老的传说,有64名战士被敌人俘虏了,敌人命令它们排成一个圈,编上号码1,2,3,64。
敌人把1号杀了,又把3号杀了,他们是隔一个杀一个这样转着圈杀。
最后剩下一个人,这个人就是约瑟夫,请问约瑟夫是多少号?
这就是数学上有名的约瑟夫问题。
给大家一个提示,敌人从l号开始,隔一个杀一个,第一圈把奇数号码的战士全杀死了。
剩下的32名战士需要重新编号,而敌人在第二圈杀死的是重新编排的奇数号码。
按照这个思路,看看你能不能解决这个问题?
(答案)
由于第一圈剩下的全部是偶数号2,4,6,8,64。
把它们全部用2除,得1,2,3,4,32.这是第二圈重新编的号码。
第二圈杀过之后,又把奇数号码都杀掉了,还剩下16个人。
如此下去,可以想到最后剩下的必然是64号。
64=222222,它可以连续被2整除6次,是从1到64中质因数里2最多的数,因此,最后必然把64号剩下。
从64=222222还可以看到,是转过6圈之后,把约瑟夫斯剩下来的。