演算法總結 約瑟夫問題

2021-07-23 15:36:05 字數 1403 閱讀 2213

約瑟夫問題:有n只猴子,按順時針方向圍成一圈選大王(編號從1到n),從第1號開始報數,一直數到m,數到m的猴子退出圈外,剩下的猴子再接著從1開始報數。就這樣,直到圈內只剩下乙隻猴子時,這個猴子就是猴王,程式設計求輸入n,m後,輸出最後猴王的編號。 

輸入資料

每行是用空格分開的兩個整數,第乙個是 n, 第二個是 m ( 0 < m, n < 300)。最後一行是: 

0 0 

輸出要求

對於每行輸入資料(最後一行除外),輸出資料也是一行,即最後猴王的編號 

輸入樣例:

6 212 4

8 30 0

輸出樣例:51

7初一看,很可能想把這道題目當作數學題來做,即認為結果也許會是以n和m為自變數的某個函式f(n,m),只要發現這個函式,問題就迎刃而解。實際上,這樣的函式很難找,甚至也許根本就不存在。用人工解決的辦法就是將 n 個數寫在紙上排成一圈,然後從1開始數,每數到第 m 個就劃掉乙個數,一遍遍做下去,直到剩下最後乙個。有了計算機,這項工作做起來就會快多了,我們只要編寫乙個程式,模擬人工操作的過程就可以了。

用陣列anloop來存放n個數,相當於n個數排成的圈;用整型變數 nptr 指向當前數到的陣列元素,相當於人的手指;劃掉乙個數的操作,就用將乙個陣列元素置0的方法來實現。人工數的時候,要跳過已經被劃掉的數,那麼程式執行的時候,就要跳過為0的陣列元素。需要注意的是,當nptr指向anloop中最後乙個元素(下標n-1)時,再數下乙個,則nptr要指回到陣列的頭乙個元素(下標0),這樣anloop才象乙個圈。

#include #include #define max_num 300

int aloop[max_num + 10];

main()

nptr --; //要回退乙個位置

if( nptr < 0 )

nptr = n - 1;

if( i == n-1 ) //最後乙隻出圈的猴子

printf("%d\n", aloop[nptr]);

aloop[nptr] = 0; //猴子出圈

} }}

上面的程式完全模擬了人工操作的過程,但因為要反覆跳過為0的陣列元素,因此演算法的效率不是很高。後文的「鍊錶」一章,採用單鏈表進行模擬來解決本題,就能省去跳過已出圈的猴子這個操作,大大提高了效率。

實現技巧

n個元素的陣列,從下標0的元素開始存放猴子編號,則迴圈報數的時候,下乙個猴子的下標就是 「(當前猴子下標 + 1 )% n」。這種寫法比用分支語句來決定下個猴子的下標是多少,更快捷而且寫起來更方便。

問題一:在陣列裡迴圈計數的時候,一定要小心計算其開始的下標和終止的下標。比如,語句15,迴圈是從0到n-1,而不是從0到n。

問題二:語句24到26回退乙個位置,易被忽略或寫錯。比如只寫了語句24,忘了處理nptr變成小於0的情況。

約瑟夫問題o n 演算法

宣告 本文僅為個人查閱方便所轉,版權為原文作者 本演算法僅適用於找出最後的勝利者,而不是得到出列序列。此方法從考慮n 1個人中最終勝利者 最後乙個沒有出列的人是誰 遞推到n個人時最終勝利者是誰。但是並不能得到出列的序列。無論是用鍊錶實現還是用陣列實現都有乙個共同點 要模擬整個遊戲過程,不僅程式寫起來...

約瑟夫演算法問題

n 個人圍成一圈,從第乙個人開始報數,數到 m 的人出列,再由下乙個人重新從 1 開始報數,數到 m 的人再出圈,依次類推,直到所有的人都出圈,請輸出依次出圈人的編號。輸入兩個整數 n,m。輸出一行 n 個整數,按順序輸出每個出圈人的編號 1 m n 100 1 leq m,n leq 100 1 ...

演算法,約瑟夫問題

跟猴子問題比較相似,最後乙個是大王。約瑟夫是最後兩個是存活。約瑟夫問題是個有名的問題 n個人圍成一圈,從第乙個開始報數,第m個將被殺掉,最後剩下乙個,其餘人都將被殺掉。例如n 6,m 5,被殺掉的順序是 5,4,6,2,3,1。function getlasttwo else 輸出活著的人 fore...