首页 > 代码库 > 约瑟夫问题

约瑟夫问题

<html>
<head>
<meta http-equiv=‘content-type‘ content=‘text/html;charset=utf-8‘ />
</head>
<body>
    <h1>约瑟夫问题解决</h1>
<?php
    class Child
    {
        public $no;
        public $next = null;

        public function __construct($no=‘‘){
            $this->no = $no;
        }
    }

    // 定义一个指向第一个小朋友的引用
    $first = null;
    $n = 4; // 表示有几个小朋友

    // 写一个函数来创建4个小朋友的环形链表
    // 深入分析下$first参数为什么加地址符&
    // 作用:把n个小孩构建出一个环形链表
    // $first变量指向了第一个小朋友
    function addChild(&$first,$n){
        // 1.头结点不能动
        $cur = null;
        for ($i = 0; $i < $n; $i++) 
        {
            $child = new Child($i+1);
            // 怎么构成一个环形链表
            if ($i==0) 
            {
                $first = $child;
                $first->next = $child;
                $cur = $first;
            }else 
            {
                $cur->next = $child;
                $child->next = $first;
                $cur = $cur->next;
            }
        }
    }

    // 显示环形链表中的所有小朋友
    // 必须要把头给出来
    function showChild($first){
        // 遍历
        $cur = $first;
        while($cur->next!=$first){
            // 显示
            echo ‘小孩的编号是‘.$cur->no.‘<br />‘;
            $cur = $cur->next;
        }

        // 当退出while循环时,已经到了环形链表的最后
        // 所以还要处理下最后这个小孩节点
         echo ‘小孩的编号是‘.$cur->no.‘<br />‘;
    }

    $m = 3; // 数3下
    $k = 2; // 从第2个开始数
    // 问题简化,从第一个小孩开始数,数2
    // 看看出圈的顺序
    function countChild($first,$m,$k){
        if ($k>$m) 
        {
            exit(‘数据设定不对‘);
        }
        // 思考:找到一个小孩,就要把他从环形链表踢出去
        // 为了能够删除某个小孩,需要一个辅助变量
        // 该变量指向的小孩在$first前面
        $tail = $first;
        while($tail->next!=$first){
            $tail = $tail->next;
        }
        
        // 考虑是从第几个人开始数数
        for ($i = 0; $i < $k-1; $i++) 
        {
            $tail = $tail->next;
            $first = $first->next;
        }

        // 当退出while循环时候 $tail就指向了最后这个小孩

        // 让$first和$tail向后移动
        // 每移动1次,相当于数了2下
        // 移动2次,相当于数了3下
        // 因为自己数的时候是不需要动的
        // 当$tail==$first说明只有一个人
        while($tail!=$first){
            for ($i = 0; $i < $m-1; $i++) 
            {
                $tail = $tail->next;
                $first = $first->next;
            }

            // 打印出出列小孩编号
            echo ‘出圈人的编号是‘.$first->no.‘<br />‘;

            // 把$first指向的节点小孩删除环形链表
            $first = $first->next;
            $tail->next = $first;
        }

        echo ‘最后留在圈圈的人的编号是‘.$tail->no;

    }

    addChild($first,4);
    showChild($first);

    // 真正的来玩儿游戏
    if ($m<$n) 
    {
        countChild($first,$m,$k);
    }
?>
</body>
</html>