约瑟夫环 & 猴王问题

来源:互联网 发布:mac 搭建vps 编辑:程序博客网 时间:2024/04/28 07:56

问题来源:

据说是新浪的一个面试题,具体题目如下:

 一群猴子排成一圈,按1,2,...,n依次编号。

然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,  再数到第m只,在把它踢出去...,

如此不停的进行下去,  直到最后只剩下一只猴子为止,那只猴子就叫做大王。

要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。

其实这是一个典型的约瑟夫环的问题,下面给出几种解法:

解法一:普通循环法

<?php/** * 猴王问题普通循环算法 * 将所有猴子编号放入一个数组 * 开始循环数组 * 判断是否只剩一个猴子,如果是,则猴王诞生,结束循环 * 猴王未诞生,继续往下执行 * 判断是否到第m个猴子了,如果到,踢出猴子,同时计数器归0,如果不到,不做任何操作,继续循环 * 数组循环结束了,应该重置数组,继续下一轮的循环 *  */function kickMonkey($n, $m) {$monkey = range(1, $n);// 给猴子编号,生成数组$i = 0;while(list($key, $val) = each($monkey)) {// each - 返回数组中当前的键/值对并将数组指针向前移动一步 if (count($monkey) == 1) {// 剩最后一个猴子,你就是猴王了 echo  $val . '成为猴王了<br />'; exit;}if (++$i == $m) {echo $monkey[$key] . '出局<br />';unset($monkey[$key]);$i = 0;}if (!current($monkey)) {// 循环到头了,重置数组reset($monkey);}}}kickMonkey(9,5);?>


得到结果

5出局1出局7出局4出局3出局6出局9出局2出局8成为猴王了

解法二:递归法

<?php/** * 猴王问题递归算法 * 递归方法的关键点是需要引入一个计数器,计数器为当前开始数的第一个猴子的索引号(注意,非猴子自身的号码) * 老样子,先将猴子编号塞入数组待用 * 判断是否只剩一个猴子,如果是,则猴王诞生,递归结束 * 获取要出局的猴子的索引号 * 将猴子踢出数组,重置猴子索引,开始递归 */function kickMonkey($monkey, $m, $index = 0) {$count = count($monkey);if ($count == 1) {echo current($monkey) . '成为猴王了<br />';exit;}/* * 获得踢出的猴子索引号 * 每次踢出下一个猴子的编号为当前踢出猴子编号+$m-1,如果数组到头,则重头开始数 * 即第一次踢出索引为(0+5-1)% 9 == 4的猴子 * 第二次踢出 (4+5-1)%8 == 0 的猴子 * 第三次踢出(0+5-1)%7 == 4的猴子 */$index = ($index + $m - 1) % $count;echo $monkey[$index] . "出局<br />";unset($monkey[$index]);kickMonkey(array_values($monkey), $m , $index);}$monkey = range(1, 9);kickMonkey($monkey, 5);?>


得到结果

5出局1出局7出局4出局3出局6出局9出局2出局8成为猴王了

解法三:数学模拟型

<?phpfunction kickMonkey($n, $m) {$index = 0;for ($i = 2; $i<=$n; ++$i) {$index = ($index + $m) % $i;}echo ($index + 1) . '成为猴王了!';}kickMonkey(9,5);?>


得到结果

8成为猴王了

原创粉丝点击