約瑟夫環的遞歸遞推問題

關於約瑟夫環的探討:課堂上學習的約瑟夫環是一個相對較麻煩的方法,而相對精簡的是遞歸的方式。

int josephus(int n, int m) {
	if(n == 1) {
		return 0;
	}
	else {
		return (josephus(n-1, m) + m) % n;
	}
}
 
int main() {
	int n, m;
	while (cin>>n) {
		if (!n) {
			break;
		}
		cin>>m;
		int result = josephus(n, m);
		cout<<result+1<<endl;
	}
	return 0;
}

遞歸相對比較簡單,並沒有使用數組結構來一個一個反映出每一局出局的人,而是直接通過遞歸得到了最終的結果。但是如此遞歸仍然不夠簡單。我們知道約瑟夫環問題本質上是一個數學問題,那麼可以使用數學的遞推思想來解決這樣一個問題。這與遞歸十分相似但更爲簡單,省去了遞歸的步驟,雖然方法類似,但由於遞歸調用函數會使時間增長,所以直接使用數學方法使用for循環時間是更爲精簡的。
int n;//共n個人
int m;//密碼爲m
Int a;//勝利者下表爲a
//下標爲0~n-1,方便取模計算。
假設此時m爲3,若11個人時6號活了下來,則當只有十個人的情況時,還可以認爲仍然是這個聰明人活了下來,但是他的編號向前移動了三個,因爲10個人相當於是11個人中的2號(第三個)出局了,所以此時勝利者下標-3,所以這個聰明人在只有十個人時應該是3號。 反之,每多一個人,這個人想要活下去就要讓自己的下標+3,當超過n-1時進行取模回到前面,這樣便可以得到遞推表達式:a=f(n,m)=[f(n-1,m)+m]%n;
由於只有一個人時勝利者爲0號,所以a從0開始,即:

for(int i=2;i<=n;i++)//對一個人沒有討論意義,故從2開始
    a=(a+m)%i;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章