目錄
模擬解決約瑟夫問題
遞推解決約瑟夫環問題
遞迴解決約瑟夫環問題
約瑟夫問題大概是這樣的:有n個人圍成一圈,編號為 1, 2,....,n 。從第乙個人開始報數(從1開始),報到 k 數字的人出圈,然後下乙個人又從 1 開始報數,...,以此類推,直到最後只剩下乙個人,問這個人的編號是多少。
#include #include using namespace std;
int n; // n 個人
int k; // 報到k數字的人出圈,從1開始報
dequeq; // 模擬圍成的圈
int main()
while(q.size() != 1)
q.pop_front(); // 將這個人出圈
}cout << q.front() << endl; // 最後就剩下乙個人,輸出即可
return 0;
}
大概思想:
直到最後還剩下乙個人,那麼他的編號一定是 0(圖中黃色框),我們所要求的也就是這個列的第乙個數字(黃色列第乙個數字)。
我們發現,我們已知的(黃色框)和我們想求的都在同一列,乙個在下邊,乙個在上邊,如果能依次遞推該多好啊
我們正是通過第 i 輪的編號求出第 i - 1輪的編號,然後依次遞推求出來的。那麼相鄰的兩輪編號之間有什麼關係呢,我們來開始分析
我們先看【開始】到【第1輪】編號之間有什麼關係,如下圖:
不難發現,他們的關係是 oldnum = (newnum + 2) % 10。
我們再來看看【第1輪】到【第2輪】編號之間的關係,看看能否找到規律,如圖:
和【開始】到【第1輪】之間的關係 oldnum = (newnum + 2) % 10 比較,彷彿如果接著分析【第2輪】到【第3輪】,是不是有 oldnum = (newnum + 2) % 8
通過查表發現,還真是這麼回事。變化的只有 % 後面的數字,而 % 前面都是固定不變的。那麼這個 % 後面的數字是什麼?
其實他就是上一輪中剩下的人數(圖中第二列)。
我們一開始只知道圖中黃色框為 0, 這樣我們就能求出黃色框上面框的數字了:此時 newnum = 0(黃色框),可以求出黃色框上面框 oldnum = (newnum + 2) % 2。然後又可以求黃色框上上面框的編號,.... ,就這樣,通過迭代直到求出一開始的編號。
#include using namespace std;
int main()
// 因為一開始的編號是 從0開始到n-1, 而題目是從1到n編號,所以+1
cout << num + 1 從遞推到遞迴的轉變不難,就如同斐波那契數列求第 n 項那樣,遞推是從底向上,而遞迴是從上至下,遞推是從已知推未知,而遞迴是一開始不知道,就問下一層,直到最底層知道,然後就向上傳。
#include using namespace std;
// 還剩下 current 人的那一輪
int num(int current, int k)else
}int main()
約瑟夫問題 約瑟夫環
約瑟夫 問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死...
約瑟夫問題 約瑟夫環
約瑟夫問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也...
約瑟夫環問題
約瑟夫環問題 問題描述 編號是1,2,n的n個人按照順時針方向圍坐一圈,每個人持有乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向的下乙個人開始重新從1報數,如此下去,直到所有人...