总时间限制: 1000ms 内存限制: 65536kB
描述
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入
每行是用空格分开的两个整数,第一个是 n, 第二个是 m ( 0 < m,n <=300)。最后一行是:
0 0
输出
对于每行输入数据(最后一行除外),输出数据也是一行,即最后猴王的编号
样例输入
6 212 48 30 0
样例输出
517
思路
一开始我是用一位数组直接模拟整个过程,样例输入输出是对的,但是超时了。
查阅资料后,得知本题可以由递推公式来得到猴王的编号,思路如下:
设由 monkeyNumber 个猴子,我们从0开始报数,报数3下就离开,即报到 3-1 = 2 的猴子离开。
- 假设只有1只猴子,他就是猴王,他的编号是0
- 假设有2只猴子,猴王编号是 (0 + 3) % 2 = 1
- 假设有3只猴子,猴王编号是 (1 + 3) % 3 = 1
- 假设有4只猴子,猴王编号是 (1 + 3) % 4 = 0
- 假设有5只猴子,猴王编号是 (0 + 3) % 5 = 3
- 假设有6只猴子,猴王编号是 (3 + 3) % 6 = 3
- ……
- 假设有
monkeyNumber只猴子,猴王编号是(上一轮的猴王编号+exitNum) %monkeyNumber.
所以递推公式如下:
%20%26%3D%20(f(monkeyNum%20-%201)%20%2B%20exitNum)%20%5C%25%5C%20monkeyNum%20%5C%5C%0Af(1%2C%20exitNum)%26%3D0%20%0A%5Cend%7Balign%7D%0A#card=math&code=%5Cbegin%7Balign%7D%0Af%28monkeyNum%2C%20exitNum%29%20%26%3D%20%28f%28monkeyNum%20-%201%29%20%2B%20exitNum%29%20%5C%25%5C%20monkeyNum%20%5C%5C%0Af%281%2C%20exitNum%29%26%3D0%20%0A%5Cend%7Balign%7D%0A)
代码
样例测试是对的,但超时的代码(数组直接硬刚果然效率不高)
#include<iostream>#include<cstring>using namespace std;int array[301] = {0};int monkeyNumber, exitNum;int main() {while(true) {scanf("%d%d", &monkeyNumber, &exitNum);if(monkeyNumber == 0) return 0;int callNumber = 1, monkeyLeft = monkeyNumber;while(monkeyLeft != 1) {for(int i = 0; i < monkeyNumber; i++ ) {if(array[i] == 666) continue;if(callNumber == exitNum) {array[i] = 666; // This monkey exitcallNumber = 1; // Reset the callNumbermonkeyLeft--;continue;}callNumber++;}}for(int i = 0; i < monkeyNumber; i++) {if(array[i] != 666) {printf("%d\n", i + 1);memset(array, 0, sizeof(array)); // Reset the value of arraybreak;}}}return 0;}
由数学递推公式得到的AC代码
#include<iostream>using namespace std;int jonseOptimal(int monkeyNumber, int exitNum) {int final = 0;for(int total = 2; total <= monkeyNumber; total++) {final = (final + exitNum) % total; // total个猴子中winner为final.}return final + 1;}int main() {int monkeyNumber, exitNum;while(true) {scanf("%d%d", &monkeyNumber, &exitNum);if(monkeyNumber == 0) return 0;printf("%d\n", jonseOptimal(monkeyNumber, exitNum));}return 0;}
