“约瑟夫环”是一个数学的应用问题:一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数, 再数到第m只,在把它踢出去…,如此不停的进行下去, 直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。
看了一些这个环的解决方案,看的时候明白,看完就忘了如何实现,突然自己写出了一种,逻辑分析加递归。
思路:
遍历猴子编号的数组,设置查找指针,到了间隔的值,就把该值置为0,表示是被剔除的猴子,然后指针重置。
遇到值为0的位置,说明该位置的猴子已经被剔除,所以不做处理,指针继续,位置计数记得要加一。继续按照上述方法查找。
位置到达数组最后一位,就重新递归遍历该数组,进行查找。
若该数组所有位置上都是0,只有一位是大于0的数,表示猴王出现。这个检查要在被剔除一个猴子的时候检查。
<?php
/*
* 判断新循环的数组中是否只有一个猴子,如果是,就是猴王,如果不是,继续递归查找。
*/
function getZreo( $array )
{
$num = 0;
foreach( $array as $key => $value )
{
if( $value == 0 )
{
$num++;
}
}
if(( count($array) - $num ) == 1){
return 1; //可以返回
} else if(count($array)==$num){
return -1; //返回值错误
} else {
return 0; //继续查找
}
}
/*
* 递归获取猴王
* @param array $array 初始的数组
* @param int $m 踢出去的间隔值
* @param int $k 查找指针
*
*/
function getMonkeyKing( $array, $m,$k=1 )
{
if( getZreo($array) == 1 )
{
return $array[0];
}
//$k = 0; //指针
$c = count($array);
$t = 1; //位置计数t 和 $c 比较,相等(表示位置已经达到数组的尾部)重新循环
foreach( $array as $key => $value )
{
//如果循环值为0,所以已经是剔除的位置,直接循环下一个值,指针不变,但是位置计数加1
if( $value == 0 )
{
if( $t == $c ) //保证t=5 value=0的时候,可以运行
{
$array = getMonkeyKing( $array, $m, $k );
return $array;
}
$t++;
continue;
}
//剔除位,置为0
if( $k==$m){
//$t是位置编号,剔除当前位置是t-1的值。
$array[$t-1] = 0;
//把指针重新赋值,因为最后要对k做加一处理,这里k=0
$k = 0;
//每次剔除一位,就判断一下数组中是否查出猴王
$result = getZreo( $array );
//查出猴王就做输出
if( $result == 1 )
{
//变换最终结果数组
foreach( $array as $k=>$v)
{
if($v>0)
{
return $v;
}
}
return $array;
}
}
//正常情况下循环完本次遍历,排除以上两种情况。
if( $t == $c ) //重新循环
{
$array = getMonkeyKing( $array, $m, $k+1 );
return $array;
}
//保证正常循环,查找指针加一,位置计数加一
$k++;
$t++;
}
}
//$arr = array(1,2,3,4,5);
$arr = range(1,11);
$m = 3;
$king = getMonkeyKing($arr, $m );
var_dump($king);
//echo getZreo(array(0,0,0,0,0));
?>