約瑟夫環問題 圓桌報數問題

2021-07-25 14:47:45 字數 1472 閱讀 8984

約瑟夫環問題:一圈共有n個人,開始報數,報到m的人自殺,然後重新開始報數,問最後自殺的人是誰?

如圖:內環表示人排列的環,外環表示自殺順序;上面n=41,m=3。

最普通辦法就是模擬整個過程:建乙個bool陣列,true表示此人還活著,false表示已經自殺。可以模擬整個過程

[cpp]view plain

copy

#include

using

namespace

std;  

intmain()  

if(count == n)  

}  if(i == n)  

i=0;  

}  delete

p;  

return

0;  

}  

模擬整個過程,複雜度為o(nm)。可以用數學方法來求解:

把問題重新描述一下:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的自殺,剩下的人繼續從0開始報數。求最後自殺者的編號。

n個人編號如下:

第乙個自殺的人是(m-1)%n,例如上圖中,41個人中,報到3的人自殺,則字乙個自殺的人的編號是(3-1)%41=2。編號(m-1)%n自殺後,剩下的人排列如下:

有人自殺後,下乙個位置m又從零開始報數,因此環應該如下:

將上面的排列順序重新編號:

問題變為(n-1)個人,報到為(m-1)的人自殺,問題規模減小了。

我們定義f(n-1)為總數為n-1個人時,最後自殺的人的序號。根據上面的對比,f(n-1)可以看成是n個人自殺掉乙個之後重新編碼組成的新問題,與重新編碼之前的序號對比多了乙個m,那麼f(n-1) + m就相當於是n個人自殺掉乙個之後,接著繼續自殺到最後乙個的序號。

即f(n) = [f(n-1) + m]%n. 

這樣一直進行下去,最後剩下編號為0的人。用函式表示:

f(1)=0

當有2個人的時候(n=2),報道(m-1)的人自殺,最後自殺的人是誰?應該是在只有乙個人時,報數時得到的最後自殺的序號加上m,因為報到m-1的人已經自殺,只剩下2個人,另乙個自殺者就是最後自殺者,用函式表示:

f(2)=f(1)+m

可以得到遞推公式:

f(i)=f(i-1)+m

因為可能會超出總人數範圍,所以要求模

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

有了遞推公式就可以在o(n)時間求出結果:

[cpp]view plain

copy

#include

using

namespace

std;  

intmain()  

cout<

/result要加1

return

0;  

}  

約瑟夫環問題(報數問題)

先說一下什麼是約瑟夫環問題,這是百科的解釋 約瑟夫環 約瑟夫問題 是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。思路 因為n...

報數問題(約瑟夫環)

解法一 用陣列模擬 include using namespace std intmain sign 實際標號的 if sign 0 sign n 1 if i n 1 cout loop sign 0 return0 解法二 從位置考慮,舉例說 nnum 5 move 212 3453 4515 ...

報數遊戲(約瑟夫環問題)

題目描述 有n個小朋友做遊戲,他們的編號分別是1,2,3 n。他們按照編號從小到大依次順時針圍成乙個圓圈,第乙個小朋友從1開始報數,依次按照順時針方向報數 報數的值加一 每個報m的人會離開隊伍,然後下乙個小朋友會繼續從1開始報數,直到只剩下乙個小朋友為止。求最後一位小朋友的編號。input 輸入兩個...