HDOJ 1276 士兵队列训练问题 超详细

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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值