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

   “约瑟夫环”是一个数学的应用问题:一群猴子排成一圈,按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;//该剩下的猴子一开始的编号。
}

 

posted @ 2019-06-11 17:24  横横竖横  阅读(1395)  评论(0编辑  收藏  举报