josephus 約瑟夫環遞歸解決分析

題目:n個人圍成一圈(編號從1到n),從第1個人開始報數,報到m的人出列,從下一個人再重新報數,報到m的人出列,如此下去,直至所有人都出列。求最后一個出列的人的編號(使用遞歸)。

分析:

遞歸問題分3步走:
1、遞歸收斂:由于m是不變的,所以只能通過n將規模不斷縮小
2、找出口:當遞歸收斂到最小單位時,能得到一個出口。即當n=1時,出局者的位置為0
3、找規律:分析已知條件,與我們需要結果的關聯。

因為我們已知最后一輪出局者在最后一輪中的位置,所以我們只需要找到后一輪出局者的位置,在上一輪中所處的位置,依次遞歸最終就能找到最后出局者在第一輪中的位置

我們知道第一輪出局者在本輪的位置(從0開始)為:f(n, m) = (m-1) % n
且第二輪第0個位置在第一輪中的位置為:m % n(注:疑惑下面有解決)
第二輪第一個位置在第一輪中的位置為:(m+1) % n,
...
第二輪第k個位置在第一輪中的位置為:(m+k) % n;
由此可推導出如下結論:
第二輪出局者在第一輪中的位置為:f(n, m) = (f(n-1, m) + m) % n
第三輪出局者在第二輪中的位置為:f(n-1, m) = (f(n-2, m) + m) % n
...
第n輪出局者在第n-1輪中的位置為: f(2, m) = (f(1, m) + m) % n
根據步驟二,出口條件可得到:f(1, m) = 0

根據遞歸性質,第二輪遞歸表達式即我們寫遞歸函數需要用到的表達式,所以最終表達式為:f(n, m) = (f(n-1, m) + m) % n
// 遞歸求最后一個幸存者的編號(從0開始)
func josephus4(n, m int) int {
    if n == 1 {
        return 0
    }
    return (josephus4(n-1, m) + m) % n
}
疑惑1:為什么第二輪開始位置在第一輪中的位置為m % n 而不是(m-1) % n + 1?

解答:分兩步:
1、證明(m-1) % n + 1 不符合我們想要的結果;
當m = kn時,即(kn - 1) % n + 1 = n,而初始位置是從0開始的,最大位置為n - 1,很明顯結果超出了。
當m > n && m != kn時或者m < n 時, 都符合我們的結果
2、證明(m+0) % n 符合結果;
當m = kn 時 kn % n = 0 符合結果
當m > n && m != kn 時或者 m < n時,都符合我們的結果

我們要把這n個人看成一個閉環,在m > 0 && n > 0的情況(m - 1) % n + 1 與 m % n 的區別在于前者不可能得到為0的位置,而后者可以。
疑惑2:為什么初始位置排列要從0開始而不從1開始呢?

解答:因為如果m = kn時,取余會得到結果0,位置從0開始比較方便,

位置從1開始分析:
第一輪出局者在本輪的位置為:f(n, m) = m % n,
第二輪第1個位置在第一輪中的位置為:m % n + 1,
...
第二輪第k個位置在第一輪中的位置為:m % n + k,如果結果大于n的話,再次取余即可。
由此可推導出如下結論:
第二輪出局者在第一輪中的位置為:f(n, m) = m % n + f(n-1, m)
第三輪出局者在第二輪中的位置為:f(n-1, m) = m % n + f(n-2, m)
...
第n輪出局者在第n-1輪中的位置為:f(2, m) = m % n + f(1, m)
根據步驟二,出口條件可得到:f(1, m) = 1 注意:因為這里第一個位置是從1開始

所以最終表達式為:f(n, m) = m % n + f(n-1, m) 需要新增條件,如果有一輪中f(n, m) > n 那么 f(n, m) = f(n, m) % n
// 遞歸求最后一個幸存者的編號(從1開始)
func josephus5(n, m int) int {
        if n == 1 {
            return 1
        }
        location := m % n + josephus5(n-1, m)
        if location > n {
            location = location % n
        }
        return location
}

以上就是我對約瑟夫環算法的理解,如有不當之處,歡迎指教!!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。