首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP實現約瑟夫環問題:循環鏈表與數學推導兩種解法

     編輯:PHP 相關知識

約瑟夫問題:從「處死犯人」到經典算法模型

約瑟夫環(Josephus Problem)描述:n 個人圍成一圈,從第 s 人開始報數,數到 m 的人出列,下一人繼續從 1 報數,循環直到剩最後一人。求最後倖存者的原始編號。

解法一:模擬循環陣列(直觀易懂)

<?php
function josephusSimulation(int $n, int $m, int $start = 1): int {
    $people = range(1, $n);
    $idx = $start - 1; // 0-based
    while (count($people) > 1) {
        $idx = ($idx + $m - 1) % count($people);
        array_splice($people, $idx, 1);
    }
    return $people[0];
}
echo josephusSimulation(5, 3); // 輸出 4

解法二:數學遞推公式(O(n) 時間 O(1) 空間)

設 f(n, m) 為 n 人報數 m 時的倖存者編號(0-based)。首輪淘汰第 (m-1)%n 人,問題縮減為 n-1 人,但起始位置偏移。遞推關係:

f(1, m) = 0
f(i, m) = (f(i-1, m) + m) % i   (i = 2..n)

最終答案為 f(n, m) + 1(轉 1-based)。

<?php
function josephusMath(int $n, int $m): int {
    $res = 0;
    for ($i = 2; $i <= $n; $i++) {
        $res = ($res + $m) % $i;
    }
    return $res + 1;
}
echo josephusMath(13, 34); // 輸出 10

解法三:遞歸模擬(教學演示用)

<?php
function josephusRecursive(array $people, int $m, int $start = 0): int {
    if (count($people) === 1) return $people[0];
    $kill = ($start + $m - 1) % count($people);
    $next = $kill % (count($people) - 1); // 下一輪起始索引
    $newPeople = array_merge(
        array_slice($people, $kill + 1),
        array_slice($people, 0, $kill)
    );
    return josephusRecursive($newPeople, $m, $next);
}
$monkeys = range(1, 13);
echo josephusRecursive($monkeys, 34);

複雜度對比與選型建議

方法時間空間適用場景
模擬陣列O(n*m)O(n)n 較小、需輸出淘汰順序
數學遞推O(n)O(1)單純求倖存者、n 極大(百萬級)
遞歸模擬O(n²)O(n)教學演示、需過程可視化

實際開發中,數學遞推法是首選;若需記錄完整淘汰序列,可用雙向循環鏈表優化模擬至 O(n log n)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved