http://my.oschina.net/stream/blog/30153?catalog=104275
今天和同学Q上聊天时候突然谈起一个问题。
问题是这样的:
一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。
设计程序如下:
01 |
<?php |
02 |
$g = 40; //全局变量:初始数组元素个数-1 |
03 |
04 |
/** |
05 |
* 解决猴子问题的函数 |
06 |
* |
07 |
* @param array 猴子数组 |
08 |
* @param int 报到此数的出列 |
09 |
* @param int 起始报数 |
10 |
* @param int 最后剩下的个数 |
11 |
*/ |
12 |
function joseph($arr, $m, $s, $q){ |
13 |
global $g; |
14 |
|
15 |
//结束递归的条件 |
16 |
$n = count($arr); |
17 |
if ($n == $q) return $arr; |
18 |
|
19 |
//循环判断并进入递归 |
20 |
/** |
21 |
* 以下循环在执行时存在效率问题,进行注释并重新修改代码 |
22 |
*/ |
23 |
/* |
24 |
$i=0; |
25 |
while ($i <= $g) { |
26 |
if ( ! isset($arr[$i])) { |
27 |
$i++; |
28 |
continue; |
29 |
} |
30 |
if ($s != $m) { |
31 |
$s++; |
32 |
} else { |
33 |
unset($arr[$i]); |
34 |
$s = 1; |
35 |
} |
36 |
$i++; |
37 |
} |
38 |
*/ |
39 |
foreach ($arr as $key => $val) { |
40 |
if ($s != $m) { |
41 |
$s++; |
42 |
} else { |
43 |
$s = 1; |
44 |
unset ($arr[$key]); |
45 |
} |
46 |
} |
47 |
|
48 |
return joseph($arr, $m, $s, $q); |
49 |
} |
50 |
51 |
//测试用例 |
52 |
for ($i = 0 ; $i <= $g; $i++) { |
53 |
$arr[] = $i; |
54 |
} |
55 |
var_dump(joseph($arr, 3, 1, 2)); |
56 |
|
57 |
/*End of php*/ |
返回结果是:
array 30 =>
int
30
即在整个猴群里你需要排在第31位(因为初始是从0开始)就可以保证你在这猴群里做大王了。
附录: 网上别人的一个程序
01 |
<span style="color:#e53333;"><?php |
02 |
/** |
03 |
* 关于约瑟夫问题求解 |
04 |
* |
05 |
*/ |
06 |
$data = array('0'=>0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); |
07 |
$begin = 1; |
08 |
echo '<pre>'; |
09 |
while(count($data) != 1) { |
10 |
echo 'begin:' . $begin; |
11 |
mark(&$data,&$begin); |
12 |
echo 'rs:'; |
13 |
var_dump($data); |
14 |
} |
15 |
echo 'last numeric:' . $begin . '<br />'; |
16 |
echo 'result:' . $data[array_rand($data)]; |
17 |
18 |
19 |
function mark($arr,$begin) { |
20 |
foreach($arr as $key=>$value) { |
21 |
if($begin++ % 3 == 0 ) { |
22 |
unset($arr[$key]); |
23 |
} |
24 |
} |
25 |
} |
26 |
?></span> |

浙公网安备 33010602011771号