约瑟夫环(猴子问题)递归思路解法

   “约瑟夫环”是一个数学的应用问题:一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数, 再数到第m只,在把它踢出去…,如此不停的进行下去, 直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入max、size, 输出最后那个大王的编号。

  对于这个问题,可以这么解:每次有猴子出列后,就给所有猴子重新编号;首先第一个出列的猴子编号NO1=(size % max)==0 ? max : (size % max)(作判断是因为size%max=0的时候,size等于max,此时编号为0,显然编号是不会等于0的,此时的编号应该是max),当第i个猴子出列后,那么从它下一个猴子开始,剩下的猴子它们的新编号应该是1,2,3.....max-1,原编号是i+1,i+2...i-1。并且,当只剩最后一只猴子的时候,此时它的新编号绝对是1; 通过观察可知,猴子的编号是与size有关的,如图下:max=6,size=3,括号里的是新编号

  然后我们发现了一个现象,新编号和原编号的差的绝对值是size=3。也就是说,编号的变化是与size有关的。

  然后我们可以归纳出,假设某个猴子的新编号是i,那么它原来的编号就是(i+size)%max,且当i+size=max时,这时它原先的编号应该为max;如新编号 i=1,原来的编号=(i+3)%6=4;i=3,新编号为i=3,原来的编号=(i+3)%6=0,则编号为6。

假如知道了还剩下某个猴子的当前编号为currentNo=x,那么该猴子上一轮的编号previousNo=(x+size)%previousMax(注意:这里的previousMax等于上一轮猴子的总数),且当(x+size)=max时,previousNo=max。

  然后我们可以用到递归的思想,我们可以从只剩1个猴子开始推导,因为我们知道最后一只猴子的新编号绝对是1,然后一直获取它上一次的编号,直到previousMax等于原来的总数Max。

  

代码:

public function yuesefu($max, $size){    $index = 1;//猴子的原编号(从1开始),因为这个当只剩最后一只猴子的时候,它的编号一定为1.    //i—>上一轮的总猴子数    for ($i = 2; $i <= $max; $i++) {     //每循环一次,就获取一次上一轮的编号,$i+1        $index = ($index + $size) % $i;      //当编号和猴子总数相等,此时编号应该设置为总数     if($index==0){        $index=$i;
      }    }    return $index;//该剩下的猴子一开始的编号。}

原文地址:https://www.cnblogs.com/aibaofeng/p/10331295.html

时间: 2024-10-24 00:05:59

约瑟夫环(猴子问题)递归思路解法的相关文章

小朋友学数据结构(1):约瑟夫环的链表解法、数组解法和数学公式解法

约瑟夫环的链表解法.数组解法和数学公式解法 约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66-70年犹太人反抗罗马的起义.约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难.在那里,这些叛乱者表决说"要投降毋宁死".于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的.约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品

一个不简洁的约瑟夫环解法

约瑟夫环类似模型:已知有n个人,每次间隔k个人剔除一个,求最后一个剩余的. 此解法为变种,k最初为k-2,之后每次都加1. 例:n=5,k=3.从1开始,第一次间隔k-2=1,将3剔除,第二次间隔k-1=2,将1剔除.依此类推,直至剩余最后一个元素. 核心思路:将原列表复制多份横向展开,每次根据间隔获取被剔除的元素,同时将此元素存入一个剔除列表中.若被剔除元素不存在于剔除列表,则将其加入,若已存在,则顺势后移至从未加入剔除列表的元素,并将其加入.如此重复n-1次.面试遇到的题,当时只写了思路,没

【好记性不如烂笔头】约瑟夫环问题之形象解法(其实就是实实在在的模拟一下游戏过程)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 约瑟夫环游戏 8 { 9 class Program 10 { 11 /* 12 * 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围. 13 * 从编号为k的

约瑟夫环的数学解法

CSDN链接 问题描述:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周围的人全部出列.求最后剩下的人的初始编号. 可以把问题转换成:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号.则所得的解加1即为原问题的解: 一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方

约瑟夫环问题的链表解法和数学解法(PHP)

约瑟夫环问题 一群猴子排成一圈,按1,2,-,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去-,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王.要求编程模拟此过程,输入m.n,输出最后那个大王的编号. 链表解法 function king($n,$m){ $monky = range(1,$n); $i = 0; while(count($monky)>1){ $i+=1; $head = array_shift($mon

Josephus环的四种解法(约瑟夫环)

约瑟夫环 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列.通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解引用别人的一个图:直观说明问题 分析: 第一步:从1开始报数为3的时候就删除3号结点第二步:从4号结点开始报数,当为3的时候删除6号结点:第三步:从7号结点开始报数,当为3的时候

约瑟夫环问题--递推解法

利用数学推导,如果能得出一个通式,就可以利用递归.循环等手段解决.下面给出推导的过程: (1)第一个被删除的数为 (m - 1) % n. (2)假设第二轮的开始数字为k,那么这n - 1个数构成的约瑟夫环为k, k + 1, k + 2, k +3, .....,k - 3, k - 2.做一个简单的映射. k         ----->  0              k+1    ------> 1              k+2    ------> 2           

bnuoj Musical Chairs 约瑟夫环非递归

/*问题描述:n个人(编号0~(n1-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号. 我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n1-1个人组成了一个新的约瑟夫环(以编号为k=m%n1的人开始): k k+1 k+2 ... n1-2, n1-1, 0, 1, 2, ... k-2 并且从k开始报0. 现在我们把他们的编号做一下转换: n1=n+1; k --> 0-->0 k+1 --> 1-->1 k+2 --> 2

约瑟夫环问题python解法

约瑟夫环问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到k的那个人被杀掉:他的下一个人又从1开始报数,数到k的那个人又被杀掉:依此规律重复下去,直到圆桌周围的人只剩最后一个. 思路是:当k是1的时候,存活的是最后一个人,当k>=2的时候,构造一个n个元素的循环链表,然后依次杀掉第k个人,留下的最后一个是可以存活的人.代码如下: class Node(): def __init__(self,value,next=None): self.valu