HDOJ 1276 士兵队列训练问题
Problem Description
某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,
凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,
继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。
Input
本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。
Output
共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。
Sample Input
2
20
40
Sample Output
1 7 19
1 19 37
这个问题可以用队列去解决,C++有个队列的类,模板被定义在< queue >头文件里,详情可以去了解一下,这里就不多介绍了。
那具体如何实现上的挑选士兵重新组队这个操作呢?
根据上面的分析我们可以写出相应代码了。
#include<iostream>
#include<queue>//C++队列类头文件
using namespace std;
int main(void)
{
int T;
cin >> T;
while (T--)
{
int arr[5];//数组用于后面的题目格式输出
int arrn = 0;//数组下标
int flag = 2;
int f = -1;//两个标记变量
int k;
int t;
int i;//计数用的
queue<int>gd;//第一个容器
queue<int>cd;//第二个容器
cin >> t;
for (i = 1; i <= t; i++)
gd.push(i);//给士兵编号
while (t > 3)//如果队列中士兵人数大于三的话进行报数出列
{
if (flag == 2)//报二的士兵出列的情况
{
f = 1;//标记容器二有人
k = 1;//每次报数都从1开始报
flag = 3;//下一轮报三的士兵出列
while (!gd.empty())//第一容器有人的情况下循环继续运行
{
if (k % 2 == 0)
{
//队列中会报二的士兵将出列
t--;//从当前队列总人数减去出列的人
gd.pop();//出列并且不能进入下一次组队
}
else
{
//未报二的士兵去第二容器重新组队
cd.push(gd.front());
gd.pop();//第一容器被逐一清理
}
k++;//标记士兵报的数
}
}
else if (flag == 3)//报三的士兵出列情况
{
f = -1;//标记容器一有人
k = 1; / 每次报数都从1开始报
flag = 2;//下一轮报二的士兵出列
while (!cd.empty())//第二器有人的情况下循环继续运行
{
if (k % 3 == 0)
{
//队列中会报三士兵将出列
t--;//从当前队列总人数减去出列的人
cd.pop();//出列并且不能进入下一次组队
}
else
{
//未报三士兵去第一器重新组队
gd.push(cd.front());
cd.pop();//第二器被逐一清理
}
k++;//标记士兵报的数
}
}
}
if (f == -1)//容器一有人所以输出容器一里的内容不输出容器二的内容
while (!gd.empty())
{
//存入数组为后面的格式输出做准备
arr[arrn] = gd.front();
arrn++;//控制数组下标
gd.pop();//逐一清空容器
}
else//容器二有人所以输出容器二里的内容不输出容器一的内容
while (!cd.empty())
{
arr[arrn] = cd.front();
arrn++;
cd.pop();
}
cout << arr[0];
for (i = 1; i < arrn; i++)
cout << ' ' << arr[i];
cout << endl;
}
return 0;
}