题目来源:http://noi.openjudge.cn/ch0302/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
#include
#include
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> 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
方法二:递推法
// 递推
// f[n]: n个人(0~n-1)m报数出列时猴王的编号
// f[n] = (f[n-1]+m)%n
// 复杂度O(n)
#include
#include
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
}