问题:
设编号为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的出列