“约瑟夫环”是一个数学的应用问题:一群猴子排成一圈,按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