約瑟夫問題:n個人圍坐成一圈,從1開始順序編號;遊戲開始,從第乙個人開始由1到m迴圈報數,
報到m的人退出圈外,問最後剩下的那個人原來的序號。
問題分析:面對這樣迴圈報數的資料,我們最容易想到的就是用陣列進行報數的模擬,最後把存活的人的編號輸出。
先貼上這種思路的**:
1 #include2 #include3 #include4 #include5 #include// find() 函式67intmain()
21 it++;22}
23 it=find(s.begin(), s.end(), 1
);24 cout<1;25
return0;
26 }
**思路是採用 vector容器來儲存每乙個人的存在狀態,如果在圈內參與報數,則值為1,退出圈後為0 。dead 是退出圈不參與報數的人數,
作為報數停止的條件,即當 dead == n-1 時,報數停止。cnt 是每乙個人報的數,當 cnt == m 時,報該數的人退出圈不再參與報數,在vector陣列中
的位置變為 0。
第十行,使用vector的迭代器來表示報數成員所對應的下標,while迴圈中即報數的模擬過程。
第十四行,因為迭代器執行過程中,可能指向 s.end() ,這一位置並不在vector
內,且沒有有意義的資料,於是把迭代器重新指向 s.begin() ,這一過程解決了環形報數中第乙個人和最後乙個人連線的問題。
第十五行,表示報數過程,vector 陣列中,此成員參與報數的話,cnt++ ,模擬報數的進行。
第十六行開始,遇到報到 m 的人,vector 中所對應的資料變為0,dead++ ,表示不再參與報數。cnt 置 0 ,表示所報數字重新從1開始(為什麼不讓cnt=0:因為下乙個人出現時,才會自增1)。
第二十三行,得到最後那個人的迭代器指向。由於 vector 迭代器是隨機訪問迭代器,支援加減運算,所以剛才得到的迭代器指向減去 s.begin() ,就是最後留下的人所對應的下標(為什麼不是他的原序號:因為下標從 0 開始計數),該結果再加一就是最後留下的人的原序號。
模擬的效率似乎不是很高,而且**量也不算少,那有什麼簡單的辦法呢?
先貼**:
遞迴呼叫:
#include#includeint joseph(int n, int
m)int
main()
題目要求出最後剩下的人的原序號,即該人所對應的下標 +1 。設 f (n , m) 是倖存者所對應的下標,
則找出 f (n , m) 與 f(n-1 , n) 的遞推關係便可以寫出遞迴函式。
以f(4, 2)舉例:
1 2 3 4
3 4 1
1 3
1我們只需要關注下標的變化即可。當 n=1 時,f(1 , m)必然等於 0 。而當 f (4 , 2) 變為 f (3 , 2) 時,
陣列整體向左移動了 m=2 。反過來可知,當 f (3 , 2) 變為 f (4 , 2) 時,陣列整體向右移動了 m=2。
即 f (3 , 2)+2 = f (4 , 2)。
考慮到實際情況為環形報數,處理後的資料可能存在溢位,所以每次結果對所剩人數 n 取餘,從而得到
實際的下標。
即 ( f (3 , 2)+2 ) % 4 = f (4 , 2)
即 ( f (n-1 , m)+m ) % n = f (n , m)
此時已得到遞推關係,則可得到倖存者所對應的下標。又因為報數時從 1 開始報數,所以下標+1便是倖存者的原序號。
由上述關係,同樣可以寫出遞推的**:
1 #include2 #include3using
namespace
std;45
intmain()
12 location++; //
下標加一就是成員原序號
13 cout<14return0;
15 }
第九行中的 q ,作為迴圈條件的同時,也是每一次遊戲中的所剩人數,協助完成第乙個成員和最後乙個成員的連線。
如果遊戲規則拓展後,情況又應該是怎樣的呢?可以看另一篇部落格:
約瑟夫環問題拓展 c/c++
理解 約瑟夫環
總結了個小經驗,有時候光靠看是看不出什麼端倪來的,還必須得動下筆,比劃比劃也許就那麼簡單 include include typedef struct node node node creatlist int n 建立乙個含 n個人的迴圈鍊錶 p next head 構建迴圈鍊錶 return he...
演算法詳解 約瑟夫問題
約瑟夫 josephus 問題 也成為約瑟夫置換 也成為約瑟夫環。n個人圍成一圈 編號1 2 3 n 這些人輪流數數 從編號為1的人開始,從1開始數 當數到m的人就會被處決 接著,後面的人再從繼續從1開始數數 如下下去,知道最後只剩下乙個人為止。問題是給定了n和m,一開始要找到什麼位置才能避免被處決...
深入理解約瑟夫環問題
1 什麼是約瑟夫環問題?約瑟夫,是乙個古猶太人,曾經在一次羅馬叛亂中擔任將軍,後來戰敗,他和朋友及另外39個人躲在一口井裡,但還是被發現了。羅馬人表示只要投降就不死,約瑟夫想投降,可是其他人堅決不同意。怎麼辦呢,他想到乙個主意 讓41個人圍成乙個圓圈,從第乙個人開始報數,數到3的那個人被旁邊的人殺死...