約瑟夫環問題,一道經典的數據結構題目


問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始報數。求勝利者的編號。

一般我們采用一個循環隊列來模擬約瑟夫環的求解過程,但是如果n比較大的時候,采用模擬的方式求解,需要大量的時間來模擬退出的過程,而且由於需要占用大量的內存空間來模擬隊列中的n個人,並不是一個很好的解法。

在大部分情況下,我們僅僅需要知道最后那個人的編號,而不是要來模擬一個這樣的過程,在這種情況下,可以考慮是否存在着一種數學公式能夠直接求出最后那個人的編號。

 

我們知道第一個人(編號一定是m%n-1) 出列之后,剩下的n-1個人組成了一個新的約瑟夫環(以編號為k=m%n的人開始):

我們先看第一個人出列后的情況,顯而易見,第一個出列的人的編號一定是m%n-1,這個人出列后,剩下的n-1個人組成了一個新的約瑟夫環,這個約瑟夫環的第一個人在最開始的環中的編號是k=m%n(就是第一個出列的人的下一個)

k  k+1  k+2  … n-2, n-1, 0, 1, 2, … k-2並且從k開始報0。

事實上,可以把這個環又映射成為一個新的環:

k  — 0

k+1 — 1

k+2 — 2

…  ….

k-2 — n-1

可以看出,這就是原問題中把n替換成n-1的情況,假設我們已經求出來在這種情況下(即n-1個數字時)最后勝利的那個人的編號是n-1中的x,那個倒推回去的n個數字時那個人的編號就是我們要求的答案,顯而易見,這個編號應該是(x+k)%n,而k=m%n,所以這個編號為(x+m)%n.

那么如何知道n-1個人下面的這個x呢,yes,就是n-2個人情況下得到的x’倒推回去,那么如何知道n-2情況下的x’呢,當然是求n-3個人,這就是一個遞歸的過程

f(1) = 0(f(1)就是現在還剩下1個人,那么無論m為幾,這個人總會出列,因此f(1)=0)

f(n) = (f(n-1)+m)%n

那么我們要求f(n),就從f(1)倒推回去即可。

#include <stdio.h>

int main()

{

int n, m, i, s = 0;

printf (“N M = “);

scanf(“%d%d”, &n, &m);

for (i = 2; i <= n; i++)

{

s = (s + m) % i;

}

printf (“\nThe winner is %d\n”, s+1);

}

轉載請注明:約瑟夫環問題,一道經典的數據結構題目


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM