题目来源:http://noi.openjudge.cn/ch0302/1748/
1748:约瑟夫问题
总时间限制: 1000ms 内存限制: 65536kB
描述
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入
每行是用空格分开的两个整数,第一个是 n, 第二个是m ( 0 < m,n <=300)。最后一行是:
0 0
输出
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号
样例输入
6 2
12 4
8 3
0 0
样例输出
5
1
7
-----------------------------------------------------
思路
方法一:模拟法
用数组模拟报数过程,复杂度O(mn)
方法二:递推法
f[n]: n个人(0~(n-1)编号)m报数时的猴王
n个人选猴王,第一轮报数后,编号为m-1的人退出。此时令编号为m,m+1,m+2,…,n-1,0,…,m-1编号变为0,1,2,…,n-2, 则从第二轮报数开始,问题转化为n-1个人选猴王问题,此时猴王的人选并没有变,只是编号相应地减小了m而已。故n人选出的猴王编号为n-1人新序列里猴王编号+m.
f[n] = (f[n-1] + m) % n
-----------------------------------------------------
代码
方法一:模拟法
// 模拟法,用数组模拟报数的过程 // 复杂度O(mn) #include<iostream> #include<fstream> #include<cstring> using namespace std; const int NMAX = 305; int n,m; int a[NMAX] = {}; int main() { #ifndef ONLINE_JUDGE ifstream fin ("0302_1748.txt"); int i,cnt=n,p=0; while ( fin >> n >> m ) { if (n==0 && m==0) { break; } if (n==1) { cout << 1 << endl; continue; } else if (m==1) { cout << n << endl; continue; } else if (n==2 && m==2) { cout << 1 << endl; } cnt = n; p = m; memset(a, 0, sizeof(a)); while (cnt>1) { a[p] = 1; cnt--; for (i=0; i<m; i++) { if (p<n) { p++; } else { p = 1; } while (a[p]!=0) { if (p<n) { p++; } else { p = 1; } } } } cout << p << endl; } fin.close(); return 0; #endif #ifdef ONLINE_JUDGE int i,cnt=n,p=0; while ( cin >> n >> m ) { if (n==0 && m==0) { break; } if (n==1) { cout << 1 << endl; continue; } else if (m==1) { cout << n << endl; continue; } else if (n==2 && m==2) { cout << 1 << endl; } cnt = n; p = m; memset(a, 0, sizeof(a)); while (cnt>1) { a[p] = 1; cnt--; for (i=0; i<m; i++) { if (p<n) { p++; } else { p = 1; } while (a[p]!=0) { if (p<n) { p++; } else { p = 1; } } } } cout << p << endl; } #endif }
方法二:递推法
// 递推 // f[n]: n个人(0~n-1)m报数出列时猴王的编号 // f[n] = (f[n-1]+m)%n // 复杂度O(n) #include<fstream> #include<iostream> using namespace std; int main() { #ifndef ONLINE_JUDGE ifstream fin ("0302_1748.txt"); int n,m,i,ans; while (fin >> n >> m) { if (n==0 && m==0) { break; } if (n==1) { cout << 1 << endl; continue; } ans = 0; for (i=2; i<=n; i++) { ans = (ans+m)%i; } cout << ans+1 << endl; } fin.close(); #endif #ifdef ONLINE_JUDGE int n,m,i,ans; while (cin >> n >> m) { if (n==0 && m==0) { break; } if (n==1) { cout << 1 << endl; continue; } ans = 0; for (i=2; i<=n; i++) { ans = (ans+m)%i; } cout << ans+1 << endl; } #endif }