约瑟夫问题:有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
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
AC代码
思路:
主要是3个变量的维护,
- sum(统计剩余猴子数量)
- count(报数)
- cur(指向所有猴子,包括已经淘汰的)
对于这个圈,用数组来代替,数组下标对应猴子的编号,数组元素存1或者0(1未淘汰,0淘汰)
然后循环不停走(直到只剩一只猴子),当cur指向的是已经淘汰的,那么count不计数(相当于不报数),否则就count++(报数),报完发现count恰好到m了,就把cur指向的元素置0(淘汰),并且count置0(剩下猴子重新报数),并且sum--(淘汰一只)。
最后注意cur一直往后走,走到数组末尾时重新从0开始(因为是个循环的圈)
#include<iostream>
using namespace std;
const int MAX = 305;
int main() {
int n, m;
while (cin >> n >> m) {
if (n == 0 && m == 0) break;
int arr[MAX] = { 0 };
for (int i = 1; i <= n; i++) arr[i] = 1;//初始化数组,1未淘汰,0淘汰
int sum = n, cur = 1, count = 0;//sum记录未淘汰猴数量,cur指向圈内所有猴(包括已经淘汰的),count是报的数
while (sum > 1) {//不止一只猴时就继续报数淘汰
if (arr[cur] == 1) {
count++;//报数
if (count == m) {//恰好报到m,淘汰该猴
arr[cur] = 0;
count = 0;//重新报数
sum--;//猴数减一
}
}
cur++;
cur = (cur == n + 1) ? 1 : cur;//cur要循环走,所以指向数组末尾时回到起始
}
//循环找最后剩下那只猴
for (int i = 1; i <= n; i++) {
if (arr[i] == 1) {
printf("%d\n", i);//注意输出的是猴的编号
break;//肯定只有一只猴王,所以输出后直接跳出,争取一点效率。。
}
}
}
return 0;
}