抽杀问题 约瑟夫问题

合集下载

抽杀问题-约瑟夫问题

抽杀问题-约瑟夫问题

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

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

据说著名犹太历史学家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个位置,之前的人都死光了,所以他们也就不知道約瑟夫与他的朋友并没有遵守游戏规则了。

数据结构与算法分析(1)——约瑟夫问题

数据结构与算法分析(1)——约瑟夫问题

数据结构与算法分析(1)——约瑟夫问题0 问题描述 据说著名犹太历史学家 Josephus有过以下的故事:在罗马⼈占领乔塔帕特后,39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓到,于是决定了⼀个⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。

然⽽Josephus 和他的朋友并不想遵从。

⾸先从⼀个⼈开始,越过k-2个⼈(因为第⼀个⼈已经被越过),并杀掉第k个⼈。

接着,再越过k-1个⼈,并杀掉第k个⼈。

这个过程沿着圆圈⼀直进⾏,直到最终只剩下⼀个⼈留下,这个⼈就可以继续活着。

问题是,给定了和,⼀开始要站在什么地⽅才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。

[1] 简单地说就是n个⼈围成⼀个圈,假设编号为0~n-1,报数范围为1~m。

从第0个⼈开始报数,每报到m,这个⼈就出局。

接着下⼀个⼈从1开始重新报数...直到剩下最后⼀个⼈。

1 问题解法 该问题常⽤解法有链表法和数组法,其他的⽐如公式法和递归法以后补充。

个⼈觉得链表法最容易理解,可能是先⼊为主的⼼理,嘿嘿嘿,下⾯就简单说⼀下。

1.1 链表法 ⾸先建⽴长度为n的循环链表,然后头结点开始报数,每第m个数删除⼀个结点,直到只剩下⼀个结点。

#include <iostream>using namespace std;struct ListNode{int val;struct ListNode* next;};/******创建循环链表******/ListNode* creatCirListNode(int n){//创建头结点ListNode *head,*node,*newnode;node = new ListNode;node->val = 0;node->next = NULL;head = node;//创建链表for (int i = 1; i < n; i++){newnode = new ListNode;newnode->val = i;node->next = newnode;node = newnode;}//将最后⼀个结点指向头结点,形成循环链表node->next = head;return head;}/******约瑟夫问题求解******/int josephSolution(ListNode* head,int m){if (NULL == head){return -1;}ListNode* pNode; //⽤来遍历结点pNode = head;while (pNode->next != pNode) //循环终⽌条件是只剩下⼀个结点{for (int i = 0; i < m-1; i++) //报数{pNode = pNode->next;}cout << pNode->next->val << "->";pNode->next = pNode->next->next; //删除链表结点}return pNode->val;}int main(){int n = 41;int m = 3;int result;ListNode* pHead;pHead = creatCirListNode(n);result = josephSolution(pHead, m);cout << result << endl;system("pause");return0;} 运⾏结果:1.2 数组法 数组法的关键是使⽤求余的⽅法循环遍历数组i=(i+1)%n,其中i是数组下标即每个⼈的标号,n是总⼈数。

抽杀问题-约瑟夫问题教学内容

抽杀问题-约瑟夫问题教学内容

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

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

据说著名犹太历史学家 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个位置,之前的人都死光了,所以他们也就不知道約瑟夫与他的朋友并没有遵守游戏规则了。

约瑟夫问题多种解决方法

约瑟夫问题多种解决方法

• • • • • • • • • • •
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个人被扔下海为止

约瑟夫斯问题探究

约瑟夫斯问题探究

约瑟夫斯问题探究学而思培优陈绍伦问题背景据说著名犹太历史学家约瑟夫斯有过以下的故事:在罗马人占领乔塔帕特后,39个犹太人与约瑟夫斯及他的朋友躲到一个洞中,他们宁死也不愿被敌人抓到,于是决定了一个自杀方式:41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.可是约瑟夫斯和他的朋友并不想遵从,他们打算选择合适的位置,留到最后避免处决.于是,他将朋友与自己安排在第16个与第31个位置,逃过了这场死亡游戏.也因此,我们以故事的主人公命名这一系列的“抽杀”问题.情景一:直线型让我们先从比较简单的直线型猫吃老鼠着手研究.【问题1】(隔1吃1)猫将4只老鼠排成一行,先隔1只,再吃1只,再隔1只,再吃1只,……一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.其实这题更像是一个“脑筋急转弯”:第一只老鼠有可能被吃掉吗?答案显而易见!结论:排成一行,隔1吃1,留下的总是第1只.【问题2】(吃1隔1)(1)猫将4只老鼠排成一行,先吃1只,再隔1只,再吃1只,再隔1只,……一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将10只老鼠排成一行,先吃1只,再隔1只,再吃1只,再隔1只,……一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.对于数字比较简单的情况,实际动手操作是得到答案的好方法!(1)4只老鼠时:第一轮猫吃掉1、跳过2、吃掉3、跳过4,留下2、4;第二轮猫吃掉2,因此最后剩下的老鼠是原来的第4只.(2)10只老鼠时:第一轮猫吃掉1、跳过2、吃掉3、跳过4、……,留下2、4、6、8、10;第二轮猫吃掉2,跳过4、吃掉6、跳过8、吃掉10,留下4、8;第三轮猫吃掉4,因此最后剩下的老鼠是原来的第8只.观察每轮留下的老鼠位置,我们发现一个有趣的规律:处于第奇数个位置的老鼠,总会被吃掉;而处于第偶数个位置的老鼠留到下一轮.而且,能留下来的老鼠,在下一轮中位置编号也发生了变化:若前一轮在第2k(k为非0自然数)个位置,下一轮将在第k个位置.换句话说,老鼠编号能分解出几个质因数2,这只老鼠就能挺过前几轮!那么结论就显而易见了:结论:排成一行,吃1隔1,留下的是第2n只.(取范围内最大值)【问题3】(吃2隔1)(1)猫将10只老鼠排成一行,先吃2只,再隔1只,再吃2只,再隔1只,……一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将20只老鼠排成一行,先吃2只,再隔1只,再吃2只,再隔1只,……一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.【问题2】中观察的是因数2的个数,因为“吃1隔1”是以每2只老鼠为一个周期.那么,本题的“吃2隔1”,会不会与因数3的个数有关呢?我们来实际操作一下:(1)10只老鼠时:第一轮猫吃掉1和2、跳过3、吃掉4和5、跳过6,……,留下3、6、9;第二轮猫吃掉3和6,因此最后剩下的老鼠是原来的第9只.还真是!9可以分解出2个因数3,是范围内最多的,它留到了最后.(2)20只老鼠时:第一轮猫吃掉1和2、跳过3、吃掉4和5、跳过6,......,留下3、6、 (18)第二轮猫吃掉3和6、跳过9、吃掉12和15、跳过18,留下9、18;第三轮猫吃掉9、因此最后剩下的老鼠是原来的第18只.这里就有个小问题了:9和18都能分解出2个因数3,为什么留到最后的18呢?重新观察第二轮的结果:9和18都有2个因数3,所以它们都挺过了第2轮.同时,由于都没有第3个因数3,如果猫要继续吃下去的话,它们都无法挺过第3轮!这么看来,18能留到最后的原因,仅仅是因为它的编号比9大而已!于是我们可以得出结论了:结论:排成一行,吃2隔1,留下的是第3n或第23n×只.(取范围内最大值)对于一般情况“排成一行,吃k隔1”,用同样的方法可以得到类似的结论,最终留下的编号是“能分解出因数(1)k+的个数最多且范围内最大的数”.【问题4】(吃1隔1吃1)(1)猫将9只老鼠排成一行,按“吃-隔-吃”的规律吃掉老鼠,一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将27只老鼠排成一行,按“吃-隔-吃”的规律吃掉老鼠,一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.“吃-隔-吃”也是每3只老鼠为一个周期的.因此我们先从总数为3n时探讨规律:(1)9只老鼠时:第一轮猫吃掉1和3、跳过2、吃掉4和6、跳过5,……,留下2、5、8;第二轮猫吃掉2和8,因此最后剩下的老鼠是原来的第5只.(2)27只老鼠时:第一轮猫吃掉1和3、跳过2、吃掉4和6、跳过5,......,留下2、5、 (26)第二轮猫吃掉2和8、跳过5、吃掉11和17、跳过14、……,留下5、14、23;第三轮猫吃掉5和23,因此最后剩下的老鼠是原来的第14只.答案的5和14,与总数9和27存在什么样的联系呢?这一规律,需要些许灵感才能观察出来:5是1~9的中间数,14是1~27的中间数.当然,这并不只是随意猜测,“中间数”的规律是可以解释的:总数为3的时候,显然留下的是正中间的第2只;总数为9的时候,我们将老鼠们分为3组:{1,2,3}、{4,5,6}、{7,8,9},留到最后的老鼠,它就应该是正中间一组的正中间一个,当然,它也处于所有数的正中间.如此类推,总数为27、81的时候,留下的也是正中间的第14只、第41只老鼠.根据等差数列的知识,我们可以用下列公式将中间数表示出来:结论:3n只,排成一行,“吃-隔-吃”,留下的是第312n+只.也就是说,答案一定在2、5、14、41、……这些数之中.我们得到了一个漂亮的结论!但是,上述结论的前提是“总数为3n只”.如果总数不是3的幂呢?【问题5】(吃1隔1吃1)(1)猫将12只老鼠排成一行,按“吃-隔-吃”的规律吃掉老鼠,一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将16只老鼠排成一行,按“吃-隔-吃”的规律吃掉老鼠,一轮结束后再次重新开始,直到最后剩下1只老鼠,这只老鼠是原来的第________只.(1)12只老鼠时:第一轮猫吃掉1和3、跳过2、吃掉4和6、跳过5,……,留下2、5、8、11;第二轮猫吃掉2和8、跳过5、吃掉11,因此最后剩下的老鼠是原来的第5只.(2)16只老鼠时:第一轮猫吃掉1和3、跳过2、吃掉4和6、跳过5,……,留下2、5、8、11、14;第二轮猫吃掉2和8、跳过5、吃掉11、跳过14、……,留下5、14;第三轮猫吃掉5,因此最后剩下的老鼠是原来的第14只.这些结果,在【问题4】中曾经也出现过,也就是说答案仍是312n+.为什么呢?在这里,我们可以用倒推的方法进行思考:(1)显然,当老鼠数量不超过3,最终将留下2;(2)若这一轮老鼠数量不超过3,那么上一轮的老鼠总数不超过9.此时,这一轮的2在上一轮的编号是5;(3)若这一轮老鼠数量不超过9,那么上一轮的老鼠总数不超过27.此时,这一轮的5在上一轮的编号是14;(4)若这一轮老鼠数量不超过27,那么上一轮的老鼠总数不超过81.此时,这一轮的5在上一轮的编号是41;……如此递推可知,活到最终轮的老鼠在每一轮的编号,倒过来数依次是2、5、14、41、……换句话说,答案应该是312n+,而且应取范围内数值最大的一个!结论:排成一行,“吃-隔-吃”,留下的是第312n+只.(取范围内最大值)情景二:封闭型如果把“猫吃老鼠”问题放在圆环上研究,又会有怎么样的变化?【问题6】(吃1隔1)(1)猫将4只老鼠围成一圈,先吃1只,再隔1只,再吃1只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将8只老鼠围成一圈,先吃1只,再隔1只,再吃1只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.简单枚举后发现,总数为4时留下的就是第4只;总数为8时留下的就是第8只. 这个结果与直线型的情况完全一致.巧合的是最后一只老鼠总被跳过,所以新的一轮又可以看成是“先吃后隔”的问题,直线型中的“从头开始”,最终结果当然一致.我们还可以用递推的思路理解:“总数为8的隔1吃1问题”,操作一轮后恰好变为“总数为4的隔1吃1问题”.也就是说,最终留下的将是第二轮的第4只,而它也是第一轮的第8只.所以,如果总数为4时留下的是最后一只,那么总数为8时留下的也是最后一只. 同理,总数为16可变为总数为8,总数为32可变为总数为16……因此得出结论:结论:2n 只,围成一圈,吃1隔1,留下的是第2n 只(最后一只).【问题7】(吃1隔1)猫将9只老鼠围成一圈,先吃1只,再隔1只,再吃1只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.从这里开始,我们要用“化归思想”——将新问题转化为已解决问题——来处理猫吃老鼠问题:总数为2n 的情况我们已经解决过了,那么如果我们考虑让猫吃掉1只,剩下8只时的最后一只,不就是我们要找的答案吗?马上尝试一下:吃掉1、跳过2,此时还有8只老鼠,3是新的起点,那么刚跳过的2就是此时的最后一只了,于是答案为第2只.更一般的情况同样可以归纳出来:(1)总数为M 时,先吃掉一些老鼠使总数变为2n ,也就是要吃掉(2)n M −只. (在这里,为了计算方便,我们希望吃掉的老鼠尽量少,也就意味着2n 要尽量大)(2)找出此时的最后一只老鼠,它正是最后一个“吃-跳”周期中跳过的一只. 由于每2只老鼠为一个“吃-跳”周期,所以最后跳过的是第2(2)n M −只老鼠. 结论:M 只,围成一圈,吃1隔1,留下的是第2(2)n M −只.(n 取范围内最大)【问题8】(隔1吃1)猫将9只老鼠围成一圈,先隔1只,再吃1只,再隔1只,再吃1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.继续用化归思想:“从1开始,先隔再吃”,不就是“从2开始的先吃后隔”吗?于是,我们仍然可以按照【问题7】的方法进行计算,最后编号加1就可以了.也就是说,答案是第 32(92)13−+=只.这里还有一个神奇的二进制方法:将总数改写为二进制形式:29(1001)=,将最高位的1移动到最右边,马上可以得到正确答案(0011)3=了!2这个“数位操作”法的原理是这样的:将最高位的1移走时,相当于原数减去了最大的2n;将1放到最右边时,其余各数全部左移一位,即数值乘2;最低位多了1,相当于给数值加1.这正是结论中的2(2)1nM−+!由于这一方法只需对二进制表达进行位移操作,在编程上很容易实现,所以正是计算机解决约瑟夫斯问题的快速算法.【问题9】(吃2隔1)(1)猫将9只老鼠围成一圈,先吃2只,再隔1只,再吃2只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将18只老鼠围成一圈,先吃2只,再隔1只,再吃2只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.实际操作发现,(1)的答案为9,(2)的答案为18.也就是说,这个结果也是与直线型完全一致的.与【问题6】类似,我们可以得出结论:结论:3n或23n×只(最后一只).×只,围成一圈,吃2隔1,留下的是第3n或23n【问题10】(吃2隔1)(1)猫将19只老鼠围成一圈,先吃2只,再隔1只,再吃2只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.(2)猫将20只老鼠围成一圈,先吃2只,再隔1只,再吃2只,再隔1只,……直到最后剩下1只老鼠,这只老鼠是原来的第________只.仿照【问题7】的“化归思想”,如果提前吃掉一部分老鼠,把总数变为3n或23n×,问题将迎刃而解.问题是,应该将总数变成哪一种呢?这里的化归,不仅要看到总数,而且要保证余下的老鼠依然是“吃2隔1”的周期.所以,我们先吃掉、跳过的部分,也必须是整数个“吃2隔1”周期.换句话说,提前吃掉的老鼠总数,必须是一个偶数.那么上述两道题的做法应该是这样的:(1)19只老鼠:19是奇数,吃掉偶数只老鼠,结果为奇数,所以应化归为奇数型即9个.先吃掉19910÷=(个)周期.−=(只),每个周期吃2隔1,即进行了1025此时,最后跳过的老鼠是第5315×=(只),因此答案为第15只.(2)20只老鼠:20是偶数,吃掉偶数只老鼠,结果为偶数,所以应化归为偶数型即18个.先吃掉20182÷=(个)周期.−=(只),每个周期吃2隔1,即进行了221此时,最后跳过的老鼠是第133×=(只),因此答案为第3只.那么,一般结论也可以类似归纳出来了:结论:M只,围成一圈,吃2隔1,若M为奇数,留下的是第(3)23nM−÷×只.(n取范围内最大)若M为偶数,留下的是第(23)23nM−×÷×只.(n取范围内最大)当然,我们可以将类似的结论推广至”封闭型的吃k隔1”问题.本文篇幅有限,在此不作赘述.感兴趣的读者可以尝试自证,深入探究!。

约瑟夫抽杀与风筝模型.宋青平

约瑟夫抽杀与风筝模型.宋青平

课堂分享集锦——宋青平分享一:约瑟夫抽杀问题【题型一】直线型抽杀知识点:直线抽杀(1)杀一个留一个,剩下第2n 个, 并且2n 尽量大 (2)杀两个留一个(若少于3个,则无法操作),剩下3n 的倍数,31n ⨯,32n ⨯ (3)杀三个留一个(若少于4个,则无法操作),剩下4n 的倍数,41n ⨯,42n ⨯,43n ⨯【例题1】(1)艾迪拿出珍藏多年的1000个馒头排成一排准备边玩边吃:从左边第一个开始,先吃一个,然后隔一个吃一个,吃到最右边再回到左边接着吃,仍然是先吃一个,然后隔一个吃一个,最后剩下的一个捏着玩,那么被捏着玩的是左数第几个馒头?(2)艾迪拿出珍藏多年的1000个馒头排成一排准备边玩边吃:从左边第一个开始,吃两个保留一个,吃到最右边再回到左边接着吃,仍然是吃两个保留一个,最后剩下的一个挂起来,那么被挂起来的是左数第几个馒头?(3)艾迪拿出珍藏多年的20个馒头排成一排准备边玩边吃:从左边第一个开始,吃两个保留一个,吃到最右边再回到左边接着吃,仍然是吃两个保留一个,直到个数少于3个不能操作为止,那么最后剩下的是左数第几个馒头?【题型二】围成一圈1、2抽杀知识点:围成一圈,杀一个留一个(1)当2n a =时,剩下第2n 个,也就是第一刀的前一个 (2)当2n a ≠时,剩下第()22n a -个【铺垫】(1)艾迪拿出珍藏多年的64个馒头排成一圈准备边玩边吃:从某一个开始作为第一个,顺时针转,先吃一个,然后隔一个吃一个,最后剩下的一个当球踢,那么被当球踢的是顺时针数第几个馒头?(2)艾迪拿出珍藏多年的20个馒头排成一圈准备边玩边吃:从某一个开始作为第一个,顺时针转,先吃一个,然后隔一个吃一个,最后剩下的一个当球踢,那么被当球踢的是顺时针数第几个馒头?【例题2】(1)1000个学生坐成一个圈,依次编号为1,2,3,,1000.现在进行1,2报数:1号学生报1后立即离开,2号学生报2并留下,3号学生报1后立即离开,4号学生报2并留下学生们依次交替报1或2,凡报1的学生立即离开,报2的学生留下,如此进行下去,直到最后还剩一个人.问:这个学生的编号是几号?(2)如下左图,七枚棋子围成一个圆圈,从①开始,每隔一个取一个,依次取走①、③、⑤、⑦、④、②,最后剩下⑥.二十枚棋子围成一个圆圈(如右图),从__________开始,每隔一个取一个,最后将只剩下一枚棋子是⑥.【练一练】这999个自然数按顺时针的方向依次排列在一个圆圈上.从1开始按顺时针(1)把1999的方向,保留1,擦去2;保留3,擦去4这样每隔一个数擦去一个数,转圈擦下去.问:最后剩下一个数时,剩下的是哪个数?(2)有100张的一摞卡片,玲玲拿着他们,从最上面的一张开始按如下的顺序进行操作:把最上面的第一张卡片舍去,把下一张卡片放在这一摞卡片的最下面.再把原来的第三张卡片舍去,把下一张卡片放在最下面.反复这样做,直到手中只剩下一张卡片,那么剩下的这张卡片是原来那一摞卡片的第几张?(3)有两副扑克牌,每副牌的排列顺序均按头两张是大王、小王,然后是黑桃、红桃、方块、梅花四种花色排列.每种花色的牌又按A ,2,3,,J ,Q ,K 顺序排列.某人把按上述排列的两幅扑克牌上下叠放在一起,然后把第一张丢掉,把第二张放在最底层,再把第三张丢掉,把第四张放在最底层,……如此进行下去,直至最后只剩下一张牌.试问所剩的这张牌是哪一张?【题型三】围成一圈1、2、3抽杀知识点:围成一圈,杀两个留一个(1)当3n a =时,剩下第3n 个,也就是第一刀的前一个;(2)当32n a m =+时,也就是a 为奇数,剩下第()332n a -⨯个; (3)(可忽略)当321n a m =++时,也就是a 为偶数,剩下第332n a -个,3n 尽量接近32a 。

抽杀问题-约瑟夫问题课件(16张PPT)

抽杀问题-约瑟夫问题课件(16张PPT)

隔一个取一个,最后将只剩下一枚棋子是⑥.
⒆⒇ ①②









⒀ ⑿⑾ ⑩

⑧ ⑨
2×(20-24)=8(号)
故事引入
提出问题
推导公式
变式拓展
【变式2】
连续自然数1,2,3,…,8899围成一圈。从1开始, 留1划掉2和3,留4划掉5和6……这么转圈划下去,最 后留下的是哪个数?
1 8
1 2
71
2
12
13
12
21
6
1
4
5
故事引入
提出问题
推导公式
变式拓展
16 15
14
1 2 3
4
13
12
11 10 9
5
6 7 8
故事引入
提出问题
推导公式
变式拓展
1.都是最后一位同学被剩下; 2.每一轮个数都会减少一半; 3.8号,16号在游戏的每一轮都报2.
2n位同学做游戏,会剩下编号最的那位同学.
律,可以得到最后留下的编号的
是37。
2 38
37 1
36 2
35
34
23 4 5
……
故事引入
提出问题
推导公式
变式拓展
若x位同学做游戏,最后留下来的同学编号为y. 设2n<x<2n+1
y=2(x-2n) ,去1留2 y=2(x-2n)+1,留1去2
故事引入
提出问题
推导公式
变式拓展
【变式1】
如下图,二十枚棋子围成一个圆圈,从 开始,每
人”职责,抓好党建工作和经济社会协 调发展 。 XX年年底,我当选村支部书记,由于是 新当选 支部书 记,初担 大任,在 班子执 行力和 群 众信服力方面存在较大问题。一年来,在各级 领导、 指导和 帮助下,我团结 村“两 委” 工作人员,紧密依靠全村党员和群众,以 践行党 的群众 路线教 育实践 活动为 契机,知

约瑟夫问题大全

约瑟夫问题大全

“约瑟夫”问题及若干变种林厚从例1、约瑟夫问题(Josephus)[问题描述]M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N报数,凡报到N的猴子退出到圈外,再从下一个猴子开始继续1~ N报数,如此循环,直到圈内只剩下一只猴子时,这只猴子就是大王。

M和N由键盘输入,1≤N,M≤10000,打印出最后剩下的那只猴子的编号。

例如,输入8 3,输出:7。

[问题分析1]这个例题是由古罗马著名史学家Josephus提出的问题演变而来的,所以通常称为Josephus(约瑟夫)问题。

在确定程序设计方法之前首先来考虑如何组织数据,由于要记录m只猴子的状态,可利用含m 个元素的数组monkey来实现。

利用元素下标代表猴子的编号,元素的值表示猴子的状态,用monkey[k]=1表示第k只猴子仍在圈中,monkey[k]=0则表示第k只猴子已经出圈。

程序采用模拟选举过程的方法,设变量count表示计数器,开始报数前将count置为0,设变量current表示当前报数的猴子编号,初始时也置为0,设变量out记录出圈猴子数,初始时也置为0。

每次报数都把monkey[current]的值加到count上,这样做的好处是直接避开了已出圈的猴子(因为它们对应的monkey[current]值为0),当count=n时,就对当前报数的猴子作出圈处理,即:monkey[current]:=0,count:=0,out:=out+1。

然后继续往下报数,直到圈中只剩一只猴子为止(即out=m-1)。

参考程序如下:program josephus1a {模拟法,用数组下标表示猴子的编号}const maxm=10000;var m,n,count,current,out,i:integer;monkey:array [1..maxm] of integer;beginwrite('Input m,n:');readln(m,n);for i:=1 to m do monkey[i]:=1;out:=0; count:=0; current:=0;while out<m-1 dobeginwhile count<n dobeginif current<m then current:=current+1 else current:=1;count:=count+monkey[current];end;monkey[current]:=0; out:=out+1; count:=0end;for i:=1 to m doif monkey[i]=1 then writeln('The monkey king is no.',i);readlnend.[运行结果]下划线表示输入Input m,n:8 3The monkey king is no.7 {时间:0秒}Input m,n:10000 1987The monkey king is no.8544 {时间:3秒}[反思]时间复杂度很大O(M*N),对于极限数据会超时。

抽杀问题约瑟夫问题

抽杀问题约瑟夫问题

阅读材料世界名题与小升初之:抽杀问题约瑟夫问题--马到成功老师在各类竞赛中,各类小升初考试中相关的世界名题出现的概率极高,这是由小升初与数学竞赛的特点决定,这特点便是:知识性,趣味性,思想性相结合;先给大家介绍这一问题的由来;据说着名犹太历史学家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个位置,之前的人都死光了,所以他们也就不知道约瑟夫与他的朋友并没有遵守游戏规则了;小升初常见抽杀考题例举:例1:把1~999这999个自然数按顺时针的方向依次排列在一个圆圈上如下图;从1开始按顺时针的方向,保留1,擦去2;保留3,擦去4……这样每隔一个数擦去一个数,转圈擦下去;问:最后剩下一个数时,剩下的是哪个数马到成功解析:可通过找规律得出,如果有2n个数,那么转一圈擦去一半,剩下2n-1个数,起始数还是1;再转一圈擦去剩下的一半,又剩下2n-2个数,起始数还是1……转了n圈后,就剩下一个数是1;如果有2n+dd<2n个数,那么当擦去d个数时,剩下2n个数,此时的第一个数是最后将剩下的数;因为擦去的第d个数是2d,所以2d+1就是最后剩下的整数;999=29+487,最后剩下的一个数是487×2+1=975;例2:1000个学生坐成一圈,依次编号为1,2,3,…,1000;现在进行1,2报数:1号学生报1后立即离开,2号学生报2并留下,3号学生报1后立即离开,4号学生报2并留下……学生们依次交替报1或2,凡报1的学生立即离开,报2的学生留下,如此进行下去,直到最后还剩下一个人;问:这个学生的编号是几号分析:这个问题与上面这题非常相似,只不过本例是报1的离开报2的留下,而上题相当于报1的留下报2的离开,由上题的结果可以推出本例的答案;本例中编号为1的学生离开后还剩999人,此时,如果原来报2的全部改报1并留下,原来报1的全部改报2并离开,那么,问题就与上面这题完全一样了;因为剩下999人时,第1人是2号,所以最后剩下的人的号码应比上题大1,是975+1=976号;为了加深理解,我们重新解这道题;解:如果有2n个人,那么报完第1圈后,剩下的是2的倍数号;报完第2圈后,剩下的是22的倍数号……报完第n圈后,剩下的是2n的倍数号,此时,只剩下一人,是2n号;如果有2n+d1≤d<2n人,那么当有d人退出圈子后还剩下2n人;因为下一个该退出去的是2d+1号,所以此时的第2d+1号相当于2n人时的第1号,而2d号相当于2n人时的第2n 号,所以最后剩下的是第2d号;由1000=29+488知,最后剩下的学生的编号是488×2=976号;例3:有100张的一摞卡片,玲玲拿着它们,从最上面的一张开始按如下的顺序进行操作:把最上面的第一张卡片舍去,把下一张卡片放在这一摞卡片的最下面;再把原来的第三张卡片舍去,把下一张卡片放在最下面;反复这样做,直到手中只剩下一张卡片,那么剩下的这张卡片是原来那一摞卡片的第几张分析与解:这100张卡片如果用线串起来,其实还是一个围成一圈的约瑟夫问题;如果上面几题的解法看不太懂,可学学这题,从最简单的情况开始找规律;下面从简单的不失题目性质的问题入手,寻找规律;列表如下:设这一摞卡片的张数为N,观察上表可知:1当N=2aa=0,1,2,3,…时,剩下的这张卡片是原来那一摞卡片的最后一张,即第2a张;2当N=2a+mm<2a时,剩下的这张卡片是原来那一摞卡片的第2m张;取N=100,因为100=26+36,2×36=72,所以剩下这张卡片是原来那一摞卡片的第72张;总结上题及例1例2:可归纳为两种情况:1、留1,杀2类:剩下号=总数-小于总数最大的2的次方数×2+12、杀1,留2类:剩下号=总数-小于总数最大的2的次方数×2记住留1要加1,杀1不用加1,总发现有学生在这点上分辨不清;因此可对照:例1:为“留1”类,可用:999-512×2+1=975例2:为“杀1”类,可用1000-512×2=976例3:为“杀1”类,可用100-64×2=72上面的512,64都是小于总数的最大的2的次方数;再看一道经变化的逆推题:例4:如下左图,七枚棋子围成一个圆圈,从①开始,每隔一个取一个,依次取走①、③、⑤、⑦、④、②,最后剩下⑥.二十枚棋子围成一个圆圈如右图,从开始,每隔一个取一个,最后将只剩下一枚棋子是⑥.实际上例就是抽杀问题的“杀1留2类”,右图可假设先从1开始取起,那根据规律留下的为:20-16×2=8号,想留下6号得逆时针倒推2枚棋子;则最后结果为19号开始; 试试我们玩的扑克牌:例5:有两副扑克牌,每副牌的排列顺序均按头两张是大王、小王,然后是黑桃、红桃、方块、梅花四种花色排列;每种花色的牌又按1,2,3,…,J,Q,K 顺序排列;某人把按上述排列的两副扑克牌上下叠放在一起,然后把第一张丢掉,把第二张放在最底层,再把第三张丢掉,把第四张放在最底层,…….如此进行下去,直至最后只剩下一张牌;试问所剩的这张牌是哪一张解:注意到:如果手中只有64张牌,按这样规则丢牌,那么后剩下的应该是第64张牌;现在手中有108张牌,多出108-64=44张,我们只需按此规定丢掉44张后,把88张牌放在手中牌的最底层时,这时手中牌恰为64张;这样,再丢下去,最后留下的就是原牌顺序的第88张,接下来的难点就涉及周期问题了,是哪张牌呢先去掉一副,再去掉黑桃、红桃各十三张,即为88-54-2×26=6;按照花色排列应为方块6;来个再难点的三个数一组的题:例6:连续自然数1,2,3,…,8899排成一列;从1开始,留1划掉2和3,留4划掉5和6……这么转圈划下去,最后留下的是哪个数可仿例1与例2;这道题留1划2和3,每次留下三分之一,显然与3的N 次方有关了;当有3n 个数时,留下的数是1号;小于8899的形如3n 的数是38=6561,故从1号开始按规则划数,划了8899-6561=2338个数后,还剩下6561个数;这划去的数中的最后一个2338÷2×3=3507,故最后留下6561个数中的第一个就是3508;这道题也可归纳出一个规律:“留1,杀2,3”型留下的这个数为=总数-小于总数的最大的3的次方数÷2×3+1考一考:连续自然数1,2,3,…,8899排成一列;从1开始,划掉1和2,留下3,划掉4和5留下6……这么转圈划下去,最后留下的是哪个数这道题可定为“杀1,2留3”型,其中的规律与答案就留给你自己去研究了;另外在最前面约瑟夫的介绍中的类型可说成为“留1、2杀3型”你探索一下这道题有什么规律; 最后见识一下隐形抽杀问题:例7:在纸上写着一列自然数1,2,……,99,100;一次操作是指将这列数中最前面的两个数划去,然后把这两个数的和写在数列的最后面,例如一次操作后得到3,4,…,99,100,3;而两次操作后得到5,6,…,99,100,3,7;这样不断进行下去,最后将只剩下一个数;问:最后剩下的数是多少最初的100个数连同后面写下的数,纸上出现的所有数的总和是多少① ③ ② ④ ⑤ ⑥ ⑦ ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇马到成功解析:在每次操作过程中,数列中添加的数等于划去的两个数之和,因此数列中所有数的和保持不变,于是当最后只剩下一个数时,它就是原来的100个数之和,为1+2+…+99+100=5050;当数列中有2n个数时,经过n次操作后将被全部划去,同时出现n个新数,并且这n 个新数之和等于原来2n个数的和;这提示我们去考虑数列包含2,2 ×2,2 ×2 ×2,…项的时刻;6个2连乘是64,当经过100-64=36次操作后,原来的数1,2,…,71,36×2=72被划去,划去的数的和是1+2+…+71+72=2628;此时数列中共有64个数,并且这64个数的和与原来100个数的和相等,是5050;从该时刻起,依次再经过32,16,8,4,2,1次操作后,纸上出现的新数的个数依次为32,16,8,4,2,1;根据前面的分析,每一轮出现的所有新数的和都是5050;从数列中有64个数变为只有1个数,操作共进行了6轮;综上所述,纸上写出的所有数之和为2628+5050+5050×6=37978;学会了抽杀问题的思路再来理解这题的设计就比较容易了;。

约瑟夫问题

约瑟夫问题




第一个人出列:从 数器 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时的问题。

约瑟夫问题

约瑟夫问题

约瑟夫问题在古代的趣味数学问题中,最著名的莫过于约瑟夫问题了。

该问题说的是:把若干人排成一圈,从某个位置数起,每数到第m个就杀掉,最后剩下的是事先指定的几个人。

这个问题很可能起源于古罗马军队中对士兵“逢十取一”的惩罚制度。

在公元4世纪的一部著作里,一位以Hegesippus为笔名的作者告诉我们,约瑟夫(Josephus)就是利用这种方式挽救自己性命的:当罗马人Vespasian 攻陷Jotapat之后,约瑟夫和另外四十个犹太人躲到一个山洞里避难。

让约瑟夫讨厌的是,除了他自己和一名特殊的朋友外,其余39人都决心自杀以便不落入罗马人之手。

尽管约瑟夫不愿意这样做,但他不敢公然提出反对;口头上只好同意。

但是,他提出了自杀行动必须按顺序进行,并建议:所有人排成一圈,随意从某一位置开始数,每数到三的人拉出圈子杀掉,最后剩下的一位自杀。

他把自己和朋友分别安排在第16和31个位置,成功地避开了死神。

在分别写于10世纪初、11世纪和12世纪的三部手稿里,我们也发现了这个问题。

文艺复兴时期,卡丹、拉姆斯(Ramus)在其数学著作中的介绍则使这个问题得以迅速流传开来。

后来,它被改编成新的版本:一艘船载有15位土耳其人和15位基督徒。

途中遇到风暴,波涛汹涌、孤舟无援、将要沉没。

为了挽救船只,保全船员,必须将一半乘客扔到海里。

于是,乘客排成一圈,从某一位置开始点数,每点到九,就把这个位置上的人扔到海里。

问如何排列方能使所有基督徒幸免于难?正确排列见下图:后人通过下列诗句中的元音字母在英文字母表的序号(a—1;e—2;i—3;o—4;u—5)来记忆上图中的排列:From numbers’aid and art,never will fame depart。

后来的欧拉、舒贝尔(Schubert)和泰特(P.G.Tait)都解决过更一般的约瑟夫问题。

英国著名制谜大师杜德内(H.E.Dudeney,1847~1930)的“猫捉老鼠”问题亦约瑟夫问题的另一形式,以下是陈怀书先生的译文:“十三鼠为猫所捕,欲逃而不能。

约瑟夫环问题的三种解法

约瑟夫环问题的三种解法

约瑟夫环问题的三种解法约瑟夫问题是个著名的问题:N个⼈围成⼀圈,第⼀个⼈从1开始报数,报到k的⼈将被杀掉,接着下⼀个⼈⼜从1开始报,直到最后剩下⼀个,求最后留下的⼈的下标。

题⽬集合解法1:暴⼒可以直接暴⼒求解,时间复杂度为O(nk)解法2:递推设f(n,k)为当n个⼈围成⼀圈时,最后留下的⼈的下标。

对于f(n-1,k)来说,其结果相当于f(n,k)的结果向前移动k\%(n-1)位。

因为对于f(n,k)来说,去掉第⼀轮报的数(k\%n)后,现在就只剩下n-1个数,并且是以(k\%(n-1)+1)作为第⼀个数,即所有数向前移动k\%(n-1)位。

现在的结果就为f(n-1,k)对于f(5,3)来说,其结果为4。

当其去掉第⼀轮报的数后,其向前移动了(3\%4)位,以4为起始,f(4,3)结果为1,对应着f(5,3)的结果4向前移动了3位所以反过来看即为,即为f(n-1,k)的结果向后移动k\%(n-1)位即f(n+1,k)=(f(n,k)+k\%n)\%n (x下标从0开始,因为取模结果为[0,n-1])时间复杂度为O(n)ll josephus2(ll n,ll k){ll pos=0;for(int len=1;len<=n;len++){pos = (pos+k)%len;}return pos+1;}递推代码解法3:如果当前这⼀位⼈没被杀掉,则他可以放在幸存者的末尾,直到幸存者数量为1所以对于下标为i的⼈,如果在他前⾯已经被杀掉了q个⼈,那么他的新的下标为n+q(k-1)+x,(1\leq x <k)如下图所⽰,最后被淘汰的编号⼀定是n*k,所以幸存者最后的编号是n*k我们现在需要从幸存者最后的编号中恢复出最初编号假设幸存者这⼀次的编号为p os_{i},在他后⾯包括他还有x位幸存者,则[pos_{i-1},pos_{i})间⼀定有x个不能被k整除的数这样才能使在他后⾯包括他还有x位幸存者。

约瑟夫问题多种解决方法

约瑟夫问题多种解决方法
1
著名约瑟夫问题一
• 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<<"----------------------------------------

有关经典约瑟夫问题的四种解法

有关经典约瑟夫问题的四种解法

有关经典约瑟夫问题的四种解法 约瑟夫问题是信息学奥赛中的⼀类经典且重要的题型,在平常的测试中屡屡出现。

通常题设可抽象为:⼀开始有n个⼈围成⼀个圈,从 1开始顺时针报数,报出m的⼈被踢出游戏.。

然后下⼀个⼈再从1开始报数,直到只剩下⼀个⼈。

 或者:曾经有个⼈在他⾝边,然⽽现在只剩他⼀个⼈。

Who are you? Who am I? Why am I here?⾛的越来越慢,⼈越来越少,可终于还是只剩⼀个了呢。

他们围成⼀圈,随机了⼀个⼈作为1号,然后逆时针依次编号。

1号开始报数,报到 1,他⾛了;然后2号开始报数,2号报了1,3 号报了2 ,于是3 号也⾛了……每⼀轮都从上⼀次出局的下⼀个⼈开始报数,第i轮从1 报到i,报i的⼈出局。

直到只剩他⼀个⼈。

却早已不记得他⾃⼰是谁。

针对不同的数据范围,可以存在如下⼏种做法:1. O(nm) O(nm)的复杂度适⽤于n,m都在30000以内的情况,此类题型较少,例如“约瑟夫游戏”⼀题,n,m<=30000,由于随着游戏的不断进⾏,需要枚举的⼈数越少,所以复杂度实际低于O(nm)。

算法思路:暴⼒模拟即可。

#include<bits/stdc++.h>using namespace std;int T,N,M; bool v[1000100];void wk(){memset(v,0,sizeof(v));scanf("%d%d",&N,&M);int t=0,num=0,pos=1;while(1){if(v[pos]){++pos;if(pos==N+1) pos=1;continue;}++num;if(num==M){if(t==N-1){printf("%d\n",pos);return;}v[pos]=1,++t,num=0;}++pos;if(pos==N+1) pos=1;}}int main(){scanf("%d",&T);while(T--) wk();return 0;}暴⼒模拟约瑟夫问题2.O(n) O(n)算法已经适⽤于⼤多数约瑟夫问题,让n<=1e7的数据范围可以被轻松解决,考虑以任意⼀⼈为起点,选出第m个⼈后的编号变化,设起始id==0,选出第m个⼈后,id−>(id+m),再回归到原来的圆形,设i表⽰第i轮游戏,那么整体的公式即为(id+m)%(n−i+1)。

约 瑟 夫 环 问 题 的 三 种 解 法

约 瑟 夫 环 问 题 的 三 种 解 法

约瑟夫问题(数学解法及数组模拟)约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。

在计算机编程的算法中,类似问题又称为约瑟夫环。

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

然而Josephus 和他的朋友并不想遵从。

首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。

接着,再越过k-1个人,并杀掉第k个人。

这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。

问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

? 以上来自百度百科约瑟夫问题是个很有名的问题:N个人围成一个圈,从第一个人开始报数,第M个人会被杀掉,最后一个人则为幸存者,其余人都将被杀掉。

例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。

约瑟夫问题其实并不难,但求解的方法多种多样;题目的变化形式也很多。

接下来我们来对约瑟夫问题进行讨论。

1.模拟解法优点 : 思维简单。

?缺点:时间复杂度高达O(m*n)当n和m的值较大时,无法短时间内得到答案。

为了叙述的方便我们将n个人编号为:1- n ,用一个数组vis 来标记是否存活:1表示死亡 0表示存活 s代表当前死亡的人数? cnt 代表当前报了数的人数用t来枚举每一个位置(当tn时 t=1将人首尾相连)? 那么我们不难得出核心代码如下:bool vis[1000]; --标记当前位置的人的存活状态int t = 0; --模拟位置int s = 0; --死亡人数int cnt = 0; --计数器if(t n) t = 1;if(!vis[t]) cnt++; --如果这里有人,计数器+1if(cnt == m) --如果此时已经等于m,这这个人死去cnt = 0; --计数器清零s++; --死亡人数+1vis[t] = 1 --标记这个位置的人已经死去coutt" "; --输出这个位置的编号}while(s != n);接下来我们来看另一种更为高效快速的解法数学解法我们将这n个人按顺时针编号为0~n-1,则每次报数到m-1的人死去,剩下的人又继续从0开始报数,不断重复,求最后幸存的人最初的编号是多少?我们只需要将最后求得的解加1就能得到原来的编号。

约瑟夫问题

约瑟夫问题

源程序: Program ex2; type nodep=^node; node=record data:integer; nest:nodep end; var head,p,q:nodep; m,n,I:integer; begin write(‘m&n:’);readln(m,n);{构造环——循 环链表}
第二种方法
分析用循环链表解决问题,首先需要构造一个循环链表,构造循环链表的方法很简单, 分析用循环链表解决问题,首先需要构造一个循环链表,构造循环链表的方法很简单, 只要将最后一个人的下一个指针指向第一个人,这样就构成一个环,如图所示, 只要将最后一个人的下一个指针指向第一个人,这样就构成一个环,如图所示,构造循环链 表以后,就可以进行删除操作,直到循环链表剩下一个人为止。 表以后,就可以进行删除操作,直到循环链表剩下一个人为止。
约瑟夫问题揭秘 Josephus Problem
Who can live at last?
约瑟夫问题的来历
据说著名犹太历史学家 Josephus有过以下的故事:在罗马 人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲 到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到, 于是决定了一个自杀方式,41个人排成一个圆圈,由第1 个人开始报数,每报数到第3人该人就必须自杀,然后再 由下一个重新报数,直到所有人都自杀身亡为止。然而 Josephus 和他的朋友并不想遵从,Josephus要他的朋友先 假装遵从,他将朋友与自己安排在第16个与第31个位置, 于是逃过了这场死亡游戏。
源程序: Program ex4; const max=100; var p:array[1..max] of integer; s1,I,j,k,w,m,n,s:integer;

简单的约瑟夫环算法

简单的约瑟夫环算法

简单的约瑟夫环算法约瑟夫环问题起源于⼀个犹太故事。

约瑟夫环问题的⼤意如下: 罗马⼈攻占了桥塔帕特,41个⼈藏在⼀个⼭洞中躲过了这场浩劫。

这41个⼈中,包括历史学家Josephus(约瑟夫)和他的⼀个朋友。

剩余的39个⼈为了表⽰不向罗马⼈屈服,决定集体⾃杀。

⼤家制定了⼀个⾃杀⽅案,所有这41个⼈围成⼀个圆圈,由第⼀个⼈开始顺时针报数,每报数为3的⼈就⽴刻⾃杀,然后再由下⼀个⼈重新开始报数,仍然是每报数为3的⼈就⽴刻⾃杀......,直到所有的⼈都⾃杀⾝亡为⽌。

约瑟夫和他的朋友并不想⾃杀,于是约瑟夫想到了⼀个计策,他们两个同样参与到⾃杀⽅案中,但是最后却躲过了⾃杀。

请问,他们是怎么做到的?package .datastruct;import java.util.Scanner;//简单的约瑟夫环求解public class Josephus {static final int Num=41; //总⼈数static final int KillMan=3; //⾃杀者报数//约瑟夫环算法static void josephus(int alive){int []man = new int[Num];int count=1;int i=0,pos=-1;while(count<=Num){do{pos=(pos+1)%Num; //环处理if(man[pos]==0) //只有没⾃杀的⼈才不等于0i++;if(i==KillMan){ //该⼈⾃杀i=0;break;}}while(true);man[pos]=count;System.out.printf("第%2d个⼈⾃杀!约瑟夫环编号为%2d",pos+1,man[pos]);if(count%2==1){System.out.printf("->");}else{System.out.printf("->\n"); //输出换⾏}count++;}System.out.println();System.out.printf("这%d个需要存活的⼈的初始位置应该排在以下序号:\n",alive);alive = Num - alive;for(i=0;i<Num;i++){if(man[i]>alive)System.out.printf("初始编号:%d,约瑟夫环编号:%d\n", i+1,man[i]);}System.out.println();}public static void main(String[] args){int alive;System.out.print("约瑟夫环问题求解!\n");System.out.print("请输⼊需要留存的⼈的数量:");Scanner input = new Scanner(System.in);alive = input.nextInt();josephus(alive);}}。

经典数学故事之约瑟夫问题

经典数学故事之约瑟夫问题

有⼀个古⽼的传说,有64名战⼠被敌⼈俘虏了,敌⼈命令它们排成⼀个圈,编上号码1,2,3,……64。

敌⼈把1号杀了,⼜把3号杀了,他们是隔⼀个杀⼀个这样转着圈杀。

最后剩下⼀个⼈,这个⼈就是约瑟夫,请问约瑟夫是多少号?
这就是数学上有名的“约瑟夫问题”。

给⼤家⼀个提⽰,敌⼈从l号开始,隔⼀个杀⼀个,第⼀圈把奇数号码的战⼠全杀死了。

剩下的32名战⼠需要重新编号,⽽敌⼈在第⼆圈杀死的是重新编排的奇数号码。

按照这个思路,看看你能不能解决这个问题?
答案解析:
由于第⼀圈剩下的全部是偶数号2,4,6,8,……64。

把它们全部⽤2除,得1,2,3,4,……32.这是第⼆圈重新编的号码。

第⼆圈杀过之后,⼜把奇数号码都杀掉了,还剩下16个⼈。

如此下去,可以想到最后剩下的必然是64号。

64=2×2×2×2×2×2,它可以连续被2整除6次,是从1到64中质因数⾥2最多的数,因此,最后必然把64号剩下。


64=2×2×2×2×2×2还可以看到,是转过6圈之后,把约瑟夫斯剩下来的。

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

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

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

据说著名犹太历史学家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个位置,之前的人都死光了,所以他们也就不知道約瑟夫与他的朋友并没有遵守游戏规则了。

小升初常见抽杀考题例举:例1:把1~999这999个自然数按顺时针的方向依次排列在一个圆圈上(如下图)。

从1开始按顺时针的方向,保留1,擦去2;保留3,擦去4……这样每隔一个数擦去一个数,转圈擦下去。

问:最后剩下一个数时,剩下的是哪个数?马到成功解析:可通过找规律得出,如果有2n个数,那么转一圈擦去一半,剩下2n-1个数,起始数还是1;再转一圈擦去剩下的一半,又剩下2n-2个数,起始数还是1……转了n圈后,就剩下一个数是1。

如果有2n+d(d<2n)个数,那么当擦去d个数时,剩下2n个数,此时的第一个数是最后将剩下的数。

因为擦去的第d个数是2d,所以2d+1就是最后剩下的整数。

999=29+487,最后剩下的一个数是487×2+1=975。

例2:1000个学生坐成一圈,依次编号为1,2,3,…,1000。

现在进行1,2报数:1号学生报1后立即离开,2号学生报2并留下,3号学生报1后立即离开,4号学生报2并留下……学生们依次交替报1或2,凡报1的学生立即离开,报2的学生留下,如此进行下去,直到最后还剩下一个人。

问:这个学生的编号是几号?分析:这个问题与上面这题非常相似,只不过本例是报1的离开报2的留下,而上题相当于报1的留下报2的离开,由上题的结果可以推出本例的答案。

本例中编号为1的学生离开后还剩999人,此时,如果原来报2的全部改报1并留下,原来报1的全部改报2并离开,那么,问题就与上面这题完全一样了。

因为剩下999人时,第1人是2号,所以最后剩下的人的号码应比上题大1,是975+1=976(号)。

为了加深理解,我们重新解这道题。

解:如果有2n个人,那么报完第1圈后,剩下的是2的倍数号;报完第2圈后,剩下的是22的倍数号……报完第n圈后,剩下的是2n的倍数号,此时,只剩下一人,是2n号。

如果有(2n+d)(1≤d<2n)人,那么当有d人退出圈子后还剩下2n人。

因为下一个该退出去的是(2d+1)号,所以此时的第(2d+1)号相当于2n人时的第1号,而2d号相当于2n人时的第2n号,所以最后剩下的是第2d号。

由1000=29+488知,最后剩下的学生的编号是488×2=976(号)。

例3:有100张的一摞卡片,玲玲拿着它们,从最上面的一张开始按如下的顺序进行操作:把最上面的第一张卡片舍去,把下一张卡片放在这一摞卡片的最下面。

再把原来的第三张卡片舍去,把下一张卡片放在最下面。

反复这样做,直到手中只剩下一张卡片,那么剩下的这张卡片是原来那一摞卡片的第几张?分析与解:这100张卡片如果用线串起来,其实还是一个围成一圈的约瑟夫问题。

如果上面几题的解法看不太懂,可学学这题,从最简单的情况开始找规律。

下面从简单的不失题目性质的问题入手,寻找规律。

列表如下:设这一摞卡片的张数为N ,观察上表可知:(1)当N=2a (a=0,1,2,3,…)时,剩下的这张卡片是原来那一摞卡片的最后一张,即第2a 张;(2)当N=2a+m (m <2a )时,剩下的这张卡片是原来那一摞卡片的第2m 张。

取N=100,因为100=26+36,2×36=72,所以剩下这张卡片是原来那一摞卡片的第72张。

总结上题及例1例2:可归纳为两种情况:1、 留1,杀2类:剩下号=(总数-小于总数最大的2的次方数)×2+12、 杀1,留2类:剩下号=(总数-小于总数最大的2的次方数)×2记住留1要加1,杀1不用加1,总发现有学生在这点上分辨不清。

因此可对照:例1:为“留1”类,可用:(999-512)×2+1=975例2:为“杀1”类,可用(1000-512)×2=976例3:为“杀1”类,可用(100-64)×2=72上面的512,64都是小于总数的最大的2的次方数。

再看一道经变化的逆推题:例4:如下左图,七枚棋子围成一个圆圈,从①开始,每隔一个取一个,依次取走①、③、⑤、⑦、④、②,最后剩下⑥.二十枚棋子围成一个圆圈(如右图),从 开始,每隔一个取一个,最后将只剩下一枚棋子是⑥.实际上例就是抽杀问题的“杀1留2类”,右图可假设先从1开始取起,那根据规律留下的为:(20-16)×2=8号,想留下6号得逆时针倒推2枚棋子。

则最后结果为19号开始。

①③ ②④⑤ ⑥ ⑦① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇试试我们玩的扑克牌:例5:有两副扑克牌,每副牌的排列顺序均按头两张是大王、小王,然后是黑桃、红桃、方块、梅花四种花色排列。

每种花色的牌又按1,2,3,…,J,Q,K顺序排列。

某人把按上述排列的两副扑克牌上下叠放在一起,然后把第一张丢掉,把第二张放在最底层,再把第三张丢掉,把第四张放在最底层,…….如此进行下去,直至最后只剩下一张牌。

试问所剩的这张牌是哪一张?解:注意到:如果手中只有64张牌,按这样规则丢牌,那么后剩下的应该是第64张牌。

现在手中有108张牌,多出108-64=44张,我们只需按此规定丢掉44张后,把88张牌放在手中牌的最底层时,这时手中牌恰为64张。

这样,再丢下去,最后留下的就是原牌顺序的第88张,接下来的难点就涉及周期问题了,是哪张牌呢?先去掉一副,再去掉黑桃、红桃各十三张,即为88-54-2×26=6。

按照花色排列应为方块6。

来个再难点的三个数一组的题:例6:连续自然数1,2,3,…,8899排成一列。

从1开始,留1划掉2和3,留4划掉5和6……这么转圈划下去,最后留下的是哪个数?可仿例1与例2。

这道题留1划2和3,每次留下三分之一,显然与3的N次方有关了。

当有3n个数时,留下的数是1号。

小于8899的形如3n的数是38=6561,故从1号开始按规则划数,划了8899-6561=2338(个)数后,还剩下6561个数。

这划去的数中的最后一个2338÷2×3=3507,故最后留下6561个数中的第一个就是3508。

这道题也可归纳出一个规律:“留1,杀2,3”型留下的这个数为=(总数-小于总数的最大的3的次方数)÷2×3+1考一考:连续自然数1,2,3,…,8899排成一列。

从1开始,划掉1和2,留下3,划掉4和5留下6……这么转圈划下去,最后留下的是哪个数?这道题可定为“杀1,2留3”型,其中的规律与答案就留给你自己去研究了。

另外在最前面约瑟夫的介绍中的类型可说成为“留1、2杀3型”你探索一下这道题有什么规律。

最后见识一下隐形抽杀问题:例7:在纸上写着一列自然数1,2,......,99,100。

一次操作是指将这列数中最前面的两个数划去,然后把这两个数的和写在数列的最后面,例如一次操作后得到3,4, (99)100,3;而两次操作后得到5,6,…,99,100,3,7。

这样不断进行下去,最后将只剩下一个数。

问:最后剩下的数是多少?最初的100个数连同后面写下的数,纸上出现的所有数的总和是多少?马到成功解析:在每次操作过程中,数列中添加的数等于划去的两个数之和,因此数列中所有数的和保持不变,于是当最后只剩下一个数时,它就是原来的100个数之和,为1+2+…+99+100=5050。

当数列中有2n个数时,经过n次操作后将被全部划去,同时出现n个新数,并且这n个新数之和等于原来2n个数的和。

这提示我们去考虑数列包含2,2 ×2,2 ×2 ×2,…项的时刻。

6个2连乘是64,当经过100-64=36次操作后,原来的数1,2,…,71,36×2=72被划去,划去的数的和是1+2+…+71+72=2628。

此时数列中共有64个数,并且这64个数的和与原来100个数的和相等,是5050。

从该时刻起,依次再经过32,16,8,4,2,1次操作后,纸上出现的新数的个数依次为32,16,8,4,2,1。

根据前面的分析,每一轮出现的所有新数的和都是5050。

从数列中有64个数变为只有1个数,操作共进行了6轮。

综上所述,纸上写出的所有数之和为2628+5050+5050×6=37978。

学会了抽杀问题的思路再来理解这题的设计就比较容易了。

相关文档
最新文档