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

問題描述: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(就是第一個出列的人的下一個)get

k  k+1  k+2  … n-2, n-1, 0, 1, 2, … k-2而且從k開始報0。數學

事實上,能夠把這個環又映射成爲一個新的環:it

k  — 0io

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);

}

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

相關文章
相關標籤/搜索