報數游戲是這樣的:有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的情況