首页 > 代码库 > 猴子选大王(约瑟夫环)

猴子选大王(约瑟夫环)

问题:

  设编号为1,2,…,n的n个人围坐一圈(每个人有一个密码(正整数)),
约定编号为k(1<=k<=n)的人从1开始报数,报到m的那个人出列,
将他的密码作为新的m值,他的下一位开始重新从1报数。
以此类推,直到所有人全部出列,计算出列顺序?

解决思路:

  循环链表

代码:

技术分享
 1 <?php
 2 /**
 3 * 设编号为1,2,…,n的n个人围坐一圈(每个人有一个密码(正整数)),
 4 * 约定编号为k(1<=k<=n)的人从1开始报数,报到m的那个人出列,
 5 * 将他的密码作为新的m值,他的下一位开始重新从1报数。
 6 * 以此类推,直到所有人全部出列,计算出列顺序?
 7 */
 8 header("Content-type: text/html; charset=utf-8");
 9 include "show.php";
10 
11 class Child
12 {
13     public $no;//编号
14     public $p;//密码
15     public $next = null;
16     
17     public function __construct($no)
18     {
19         $this->no = $no;
20     }
21 }
22 
23 function add(&$first, $n)
24 {
25     //头指针不能动
26     $cur = $first;
27     //循环创建节点
28     for($i=1; $i<=$n; ++$i)
29     {
30         $person = new Child($i);
31         $person->p = mt_rand(1, $n);
32         if (1 == $i)//只有一个节点的时候需要单独作处理,创建循环链表
33         {
34             $first = $person;
35             $first->next = $person;
36             $cur = $first;
37         } else {
38             $cur->next = $person;
39             $person->next = $first;
40             $cur = $cur->next;
41         }
42     }
43 }
44 
45 function josephu(&$first, $k=1, $m=2)
46 {
47     //1.先创建一个尾指针,方便后续删除
48     $cur = $first;
49     while($cur->next != $first){
50         $cur = $cur->next;
51     }
52     
53     //2.从第$k个元素开始数
54     for($i=1; $i<$k; ++$i)
55     {
56         $first = $first->next;
57         $cur = $cur->next;
58     }
59     
60     //3.开始出列
61     $lists = [];
62     while($cur != $first)
63     {
64         for($i=1; $i<$m; ++$i)
65         {
66             $first = $first->next;
67             $cur = $cur->next;
68         }
69         //$first即为要删除的元素
70         $lists[] = $first->no;
71         $m = $first->p;
72         $cur->next = $first->next;
73         $first = $first->next;
74         
75     }
76     $lists[] = $first->no;
77     show($lists);
78 }
79 
80 $first = null;//初始化的时候,$first等于空指针
81 
82 //1.先创建4个节点的循环链表
83 add($first, 4);
84 
85 //show($first);//打印验证循环链表创建是否正确
86 
87 //2.出列
88 josephu($first, 2, 2);//从第二个开始数数,数到2的出列
View Code

 

猴子选大王(约瑟夫环)