約瑟夫環問題的兩種解法(詳解)

2021-08-16 14:49:14 字數 1931 閱讀 9033

題目:

josephus有過的故事:39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人抓。於是決定了自殺方式,41個人排成乙個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺。然後下乙個重新報數,直到所有人都自殺身亡為止。然而josephus 和他的朋友並不想遵從,josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。

對於這個題目大概兩種解法:

一、使用迴圈鍊錶模擬全過程

#includeusing namespace std;

/************約瑟夫問題****************/

typedef struct clinklist

node;

int main()

r->next =l->next; //讓最後乙個結點指向第乙個有資料結點

node *p;

p = l->next;

delete l; //刪除第乙個空的結點

///模擬解決約瑟夫問題

coutdata

p->next = p->next->next; //將該節點從鍊錶上刪除。

p = p->next;

}cout

我們假設這41個人編號是從0開始,從1開始報數,第3個人自殺。

1、最開始我們有這麼多人:

[ 0 1 2 3 4 5 ... 37 38 39 40 ]

2、第一次自殺,則是(3-1)%41=2 這個人自殺,則剩下:

[ 0 1 3 4 5 ... 37 38 39 40 ]
3、然後就是從編號為3%41=3的人開始從1報數,那麼3號就相當於頭,既然是頭為什麼不把它置為0,這樣從它開始就又是與第1,2步一樣的步驟了,只是人數少了乙個,這樣不就是遞迴了!!!就可以得到遞迴公式。想法有了就開始做:

4、把第2步中剩下的人編號減去3對映為:

[ -3 -2 0 1 2 ... 34 35 36 37 ]
5、出現負數了,這樣不利於我們計算,既然是環形,37後面報數的應該是-3,-2,那麼把他們加上乙個總數(相當於加上360度,得到的還是它)

[ 38 39 0 1 2 3 ... 34 35 36 37 ]
6、這樣就是乙個總數為40個人,報數到3殺乙個人的遊戲。

這次自殺的是第5步中的(3-1)%40=2號,但是我們想要的是第2步中的編號(也就是最初的編號)

那最初的是多少?對應回去是5;

這個5是如何得到的呢?是(2+3)%41得到的。大家可以把第5步中所有元素對應到第2步都是正確的。

7、接下來是

[ 35 36 37 38 0 1 2... 31 32 33 34 ]
自殺的是(3-1)%39=2,先對應到第5步中是(2+3)%40=5,對應到第2步是(5+3)%41=8。

8、這下看出來規律了把:

我們是正著推的,如果反過來推導,每次剩下的人的編號為f(i),剩乙個人的時候編號一定為0,兩個人為0,1,以此類推,則利用以下公式可以推導出每次剩下的人。

f(1)=0;

f(i)=(f[i-1]+m)%i;(i>1)

**如下:

#includeusing namespace std;

///推導公式方法

約瑟夫環的兩種解法

n個人想玩殘酷的死亡遊戲,遊戲規則如下 n個人進行編號,分別從1到n,排成乙個圈,順時針從1開始數到m,數到m的人被殺,剩下的人繼續遊戲,活到最後的乙個人是勝利者。請輸出最後乙個人的編號。input 輸入n和m值。m 1。output 輸出勝利者的編號。sample input 5 3sample ...

約瑟夫環的兩種實現

方法一 用乙個陣列存放每個元素,再用乙個bool陣列存放每個元素是否還在那個佇列中。每次出列乙個元素,將其對應的那個bool值置為false。迴圈輸出第m個元素直到只剩下乙個元素在佇列中。不過這個時間複雜度比較高。includeusing namespace std 時間複雜度高的方法 define...

約瑟夫環問題數學解法

首先一開始的序列 序列1 1,2,3,4,n 2,n 1,n 此時出佇列的第乙個人,位置為k,號碼肯定是m n。這個應該沒有問題,也就是取餘操作使得陣列類似能夠有迴圈的功能。此時序列2 1,2,3,4,k 1,k 1,n 2,n 1,n 此時k出佇列,序列2中為n 1個人了。根據序列2,得到序列3 ...