約瑟夫問題

<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>
相關文章
相關標籤/搜索