問題描述:有n個人坐成一圈,編號為1到n,從編號為1的人開始傳遞熱馬鈴薯。m次傳遞之後,持有熱馬鈴薯的人退出遊戲,圈縮小,然後遊戲從退出人下面的人開始,繼續進行。最終留下來的人獲勝。這樣,如果m=0,n=5,那麼參加遊戲的人依次推出,5號獲勝。如果m=1,n=5,那麼退出的順序是2、4、1、5。
方法1:使用迴圈鍊錶的資料結構來解決。
**如下:
circularlist.h
//---------【利用迴圈鍊錶解決約瑟夫環問題】------------
#ifndef __circularlist__
#define __circularlist__
#include // 迴圈鍊錶的實現
class circularlist
};public:
circularlist(int n)
curr->next = first;
} ~circularlist()
delete first;
first = null;
} void printlist() const
std::cout << std::endl;
} // 時間複雜度:o(mn)
void erase(int m)
listnode *curr = first;
while(curr->next != curr)
std::cout << "the person out: " << curr->val << "\n";
prev->next = curr->next;
delete curr;
curr = prev->next;
first = curr;
printlist();
} first = curr;
std::cout << "the winner is " << curr->val;
}private:
listnode *first;
};#endif
main.cpp
//-----------------【約瑟夫環問題】--------------------
#include "circlelist.h"
using namespace std;
int main(int argc, char const *argv)
方法2:使用數學推導。
原問題可以解釋為編號為1到n的人,從編號為1的人開始喊數字0,下乙個喊數字1,依次類推,直到有人喊數字m,則這個人退出遊戲。下乙個人又從0開始喊,直到只剩乙個人。
原序列1:1,.......,k-2,k-1,k,......,n(其中序號k-1出列)。
由推導可得,出列的序號為(m+1)%n(因為m可能比n大),所以有k-1=(m+1)%n,即k=(m+2)%n。
出列後得到序列2:1,.......,k-2,k,......,n。
將前面的k-2個元素放到序號n的後面,則得到序列3:k,......,n,1,.......,k-2。
將序號1及後面的序號全部加上n,則得到序列4:k,......,n,n+1,......,n+k-2。
再將全部序號減去k-1,得到序列5:1,......,n-1。
由於最後的勝利者在序列1中,也肯定在序列5中,設其在序列5中的序號為x,在序列1中的序號為x』,現在問題變為推導x和x'的關係。
從序列5到序列4,全部加上k-1即可,即x'=x+k-1。
其中比較難的的推導是從序列4到序列3,也就是將序列n+1,......,n+k-2這一部分變為1,......,k-2,其實就是對n取餘數,即x'=(x+k-1)%n。由於k=(m+2)%n,故x'=(x+m+1)%n。需要注意的是此時n會變為0,需要將其修改回來。
從序列3到序列2和序列1,序號沒有改變。
所以我們可以總結如下:
設i為剩餘參加比賽的人數,f[i]為最終勝利者的序號,有
f[1]=1;f[i]=(f[i-1]+m+1)%i(i>1);如果f[i]==0,f[i]=i。
**如下:
#include int main(int argc, char const *argv)
printf("%d\n", winner);
return 0;
}
這種型別的問題還有其它的類似遞推公式:
f[1]=0;f[i]=(f[i-1]+m)%i(i>1):人的序號為0到n-1,數字從1開始喊到m的情況。
f[1]=1;f[i]=(f[i-1]+m)%i(i>1);如果f[i]==0,f[i]=i:人的序號為1到n,數字從1開始喊到m的情況。
將上面第一種情況的結果加上1也可得到第二種情況的結果,或者寫成f[1]=1;f[i]=(f[i-1]+m-1)%i
+ 1(i>1)。
約瑟夫問題 約瑟夫環
約瑟夫 問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死...
約瑟夫問題 約瑟夫環
約瑟夫問題 有時也稱為約瑟夫斯置換,是乙個出現在電腦科學和數學中的問題。在計算機程式設計的演算法中,類似問題又稱為約瑟夫環。又稱 丟手絹問題 據說著名猶太歷史學家 josephus有過以下的故事 在羅馬人占領喬塔帕特後,39 個猶太人與josephus及他的朋友躲到乙個洞中,39個猶太人決定寧願死也...
約瑟夫環問題
約瑟夫環問題 問題描述 編號是1,2,n的n個人按照順時針方向圍坐一圈,每個人持有乙個密碼 正整數 一開始任選乙個正整數作為報數上限值m,從第乙個人開始順時針方向自1開始順序報數,報到m時停止報數。報m的人出列,將他的密碼作為新的m值,從他在順時針方向的下乙個人開始重新從1報數,如此下去,直到所有人...