士兵佇列訓練問題(連結串列練習)
阿新 • • 發佈:2021-02-07
技術標籤:杭電OJ
Problem Description
某部隊進行新兵佇列訓練,將新兵從一開始按順序依次編號,並排成一行橫隊,訓練的規則如下:從頭開始一至二報數,凡報到二的出列,剩下的向小序號方向靠攏,再從頭開始進行一至三報數,凡報到三的出列,剩下的向小序號方向靠攏,繼續從頭開始進行一至二報數。。。,以後從頭開始輪流進行一至二報數、一至三報數直到剩下的人數不超過三人為止。
Input
本題有多個測試資料組,第一行為組數N,接著為N行新兵人數,新兵人數不超過5000。
Output
共有N行,分別對應輸入的新兵人數,每行輸出剩下的新兵最初的編號,編號之間有一個空格。
Sample Input
2
20
40
Sample Output
1 7 19
1 19 37
分析題意:
- 將n個數依次按1,2,1,2,1,2… … 標號,然後刪除下標為2的數
- 再將剩下的數依次按1,2,3,1,2,3… … 標號,然後刪除下標為3的數
- 迴圈以上兩步
樣例1:
① 把1~20按照1,2,1,2,1,2… …排序,結果如圖:
② 刪除下標為2的數並按照1,2,3,1,2,3… … 排序,結果如圖:
③ 刪除下標為3的數並按照1,2,1,2,1,2…排序,結果如圖:
④ 刪除下標為2的數並按照1,2,3,1,2,3…排序,結果如圖:
⑤ 刪除下標為3的數並按照1,2,1,2…排序,結果如圖:
此時人數不超過三人,故輸出結果1 7 19
注意:
- erase( it )的作用是刪除迭代器指向的當前元素,並返回該迭代器下一引數的迭代器。寫法:it = li.erase(it);
- 注意最後一個元素後不能帶空格,格式問題
AC程式碼
#include <cstdio>
#include <list>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int t;//多組資料
cin >> t;
list<int> li;//STL:連結串列
while (t--)
{
li.clear();//清空上次操作的資料
int n;
cin >> n;
for (int i = 1;i <= n;i++) li.push_back(i);//輸入1~n個數
int k = 2;
list<int>::iterator it;
while (li.size() > 3)//連結串列中的元素個數大於3
{
int num = 1;//num模擬連結串列中元素的下標1,2,1,2,1,2... ...
for (it = li.begin();it != li.end();)
{
if (num++ % k == 0)
{
it = li.erase(it);//這句話執行以後會返回下一個迭代器
}else it++;
}
//若以上for迴圈對2取模,則下一次應該對3取模;
//若以上for迴圈對3取模,則下一次應該對2取模;
//即k == 2? k = 3:k = 2;
if (k == 2) k = 3;
else k = 2;
}
//輸出結果(注意最後一個元素後不能帶空格)
for (it = li.begin();it != li.end();it++)
{
if (it != li.begin()) cout << " ";
cout << *it;
}
cout << endl;
}
return 0;
}
本題需要著重理解以下程式碼如何做到輪流對2和3取模,並且上輪刪除對2取模為0的數,下輪刪除對3取模為0的數
while (li.size() > 3)
{
int num = 1;
for (it = li.begin();it != li.end();)
{
if (num++ % k == 0)
{
it = li.erase(it);
}else it++;
}
if (k == 2) k = 3;
else k = 2;
}