报数游戏是这样的:有n个人围成一圈,按顺序从1到n编好号。从第一个人开始报数,报到m(m<n)的人退出圈子;下一个人从1开始报数,报到m的人退出圈子。如此下去,直到留下最后一个人。其中n是初始人数;m是游戏规定的退出位次(保证为小于n的正整数)。要求用队列结构完成。输出数字间以空格分隔,但结尾不能有多余空格。
输入样例:
5 3
输出样例:
3 1 5 2 4
输入样例:
5 6
输出样例:
error!
看到这个题,想到是用STL set来做
下面是最开始的代码
#include <iostream> #include<set> using namespace std; int main() { set<int> s; int m, n; cin >> n >> m; if (m >= n) { cout << "error!"; return 0; } for (int i = 0; i < n; i++) { s.insert(i + 1); } set<int>::iterator it; it = s.begin(); int flag = 0; while (s.size() != 0) { for (int i = 1; i < m; i++) { if (!(it != s.end())) { it = s.begin(); } it++; } if (!(it != s.end())) { it = s.begin(); } if (flag == 0) { cout << *it; flag = 1; } else { cout << " " << *it; } int c = *it; s.erase(c); int j = 1; it = s.find((c + 1) % n); if (!(it != s.end())) { it = s.begin(); } } }
测试结果:
但是看这一句 it = s.find((c + 1) % n); 假设(c+1)%n在set中没有找到的话,返回给it的地址就是s.end() 但是假设c+1没找到后面还有c+2的话就会出错,所以我手写了一个测试点,n=8,m=3。
按照题目意思推理得出: 3 6 1 5 2 8 4 7
但是按照我写的代码得出的结果是:3 6 1 5 7 8 2 4
所以改进版代码为:
#include <iostream> #include<set> using namespace std; int main() { set<int> s; int m, n; cin >> n >> m; if (m >= n) { cout << "error!"; return 0; } for (int i = 0; i < n; i++) { s.insert(i+1); } set<int>::iterator it; it = s.begin(); int flag = 0; while (s.size() != 0) { for (int i = 1; i < m; i++) { if (!(it != s.end())) { it = s.begin(); } it++; } if (!(it != s.end())) { it = s.begin(); } if (flag == 0) { cout << *it; flag = 1; } else { cout <<" "<< *it; } int c = *it; s.erase(c); int j = 1; while (1) { it = s.find((c + j) % n); if (it != s.end()) break; else j++; if (j == n) { break; it = s.end(); } } if (!(it != s.end())) { it = s.begin(); } } }
得出结果:3 6 1 5 2 8 4 7
PTA提交结果:正确
同一个测试点两种代码给出的结果是不一样的,而PTA上提交都是正确的,说明测试点没有考虑到n远大于m的情况