[TOJ1133]Eeny Meeny Moo 約瑟夫問題

Surely you have made the experience that when too many people use the Internet simultaneously, the net becomes very, very slow.
To put an end to this problem, the University of Ulm has developed a contingency scheme for times of peak load to cut off net access for some cities of the country in a systematic, totally fair manner. Germany's cities were enumerated randomly from 1 ton. Freiburg was number 1, Ulm was number 2, Karlsruhe was number 3, and so on in a purely random order.

Then a number m would be picked at random, and Internet access would first be cut off in city 1 (clearly the fairest starting point) and then in everymth city after that, wrapping around to 1 after n, and ignoring cities already cut off. For example, ifn=17 and m=5, net access would be cut off to the cities in the order [1,6,11,16,5,12,2,9,17,10,4,15,14,3,8,13,7]. The problem is that it is clearly fairest to cut off Ulm last (after all, this is where the best programmers come from), so for a given n, the random number m needs to be carefully chosen so that city 2 is the last city selected.

Your job is to write a program that will read in a number of cities n and then determine the smallest integerm that will ensure that Ulm can surf the net while the rest of the country is cut off.

Input Specification

The input file will contain one or more lines, each line containing one integer n with 3 ≤ n < 150, representing the number of cities in the country.
Input is terminated by a value of zero (0) for n.

Output Specification

For each line of the input, print one line containing the integer m fulfilling the requirement specified above.

Sample Input

3
4
5
6
7
8
9
10
11
12
0

Sample Output

2
5
2
4
3
11
2
3
8
16


約瑟夫問題描述與解決方案

初始情況: 0, 1, 2 ......n-2, n-1 (共n個人)


第一個人(編號一定是(m-1)%n,設之爲(k-1) ,讀者可以分m<n和m>=n的情況分別試下,就可以得出結論) 出列之後,

剩下的n-1個人組成了一個新的約瑟夫環(以編號爲k==m%n的人開始):

 k  k+1  k+2  ... n-2, n-1, 0, 1, 2, ...,k-3, k-2 


現在我們把他們的編號做一下轉換:


x' -> x

k     --> 0
k+1   --> 1
k+2   --> 2
...
...
k-2   --> n-2
k-1   --> n-1


變換後就完完全全成爲了(n-1)個人報數的子問題,假如我們知道這個子問題的解:例如x是最終的勝利者,那麼根據上面這個表把這個x變回去不剛好就是n個人情況的解嗎!


x ->x'(這正是從n-1時的結果反過來推n個人時的編號!)

0 -> k

1 -> k+1

2 -> k+2

...

...

n-2 -> k-2

變回去的公式 x'=(x+k)%n


那麼,如何知道(n-1)個人報數的問題的解?只要知道(n-2)個人的解就行了。(n-2)個人的解呢?只要知道(n-3)的情況就可以了 ---- 這顯然就是一個遞歸問題:


令f[i]表示i個人玩遊戲報m退出最後勝利者的編號,最後的結果就是f[n]


遞推公式


f[1]=0;

f[i]=(f[i-1]+k)%i = (f[i-1] +m%i) % i = (f[i-1] + m) % i ;  (i>1)


解題思想:有n個城市,第一個總是最先退出,相當於從第二個開始按1,2,……m,1,2……m這樣報數,問題實際上可抽象成n-1個城市的Josephus問題,注意josephus思想是按0,1,……n-1編號的,又加上是從第二個城市開始報數,求得的最後一個城市的實際編號=Josephus方法求得的編號+1+1。

result == 0 時爲所求。

#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;

int main(){
	int n;
	while (cin >> n && n){
		int m;
		for (m = 2;;m++){
			int result = 0;
			for (int i = 2;i < n;i++){
				result = (result + m ) % i ;
			}
			//cout << result << endl;
			if (result == 0) {
				cout << m << endl;
				break;
			}
		}
	}
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章