士兵队列训练问题 两种方法:queue模拟、list模拟
问题描述:
某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数。。。,以后从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。
输入:
本题有多个测试数据组,第一行为组数N,接着为N行新兵人数,新兵人数不超过5000。
输出:
共有N行,分别对应输入的新兵人数,每行输出剩下的新兵最初的编号,编号之间有一个空格。
样例输入:
2
20
40
样例输出:
1 7 19
1 19 37
queue模拟思路:从第一个人开始出队,让他报数,如果等于K就舍弃,否则就将他再入队。每循环一周后将K值改变一次,循环直到队列中少于三个元素为止。
AC代码(C++):
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
scanf("%d",&n);
while(n--){
int num;
scanf("%d",&num);
queue<int> q;
for(int i=0;i<num;i++){
q.push(i+1);
}
int k=2,i=0; //记录报数规则k=2:1~2,k=3:1~3
int m=0; //记录是否循环一圈
int p=q.size();
while(p>3){
int x=q.front();
q.pop();
i++;
if(i==k){
i=0;
}
else{
q.push(x); //不报k的人再入队
}
m++;
if(m==p){ //如果循环一圈就重置
k==2?k=3:k=2; //更改报数规则
p=q.size();
i=0;
m=0;
}
}
while(!q.empty()){
if(q.size()==1){
printf("%d",q.front()); //最后一个后面没有空格
}
else{
printf("%d ",q.front());
}
q.pop();
}
printf("\n");
}
return 0;
}
list容器模拟思路:使用迭代器对存在list里的n个人进行遍历,找到每个报K的人(%k==0),将其删除(erase()),循环往复,直到列表中的元素个数不超过三个。
AC代码(C++):
#include <bits/stdc++.h>
using namespace std;
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int k=2;
list<int> mylist;
list<int>::iterator it;
for(int i=0;i<n;i++){
mylist.push_back(i+1);
}
while(mylist.size()>3){
int num=1;
for(it=mylist.begin();it!=mylist.end();){
if(num++%k==0){
it = mylist.erase(it);
}
else{
it++;
}
}
k==2?k=3:k=2;
}
for(it=mylist.begin();it!=mylist.end();it++){
if(it!=mylist.begin()){
printf(" ");
}
printf("%d",*it);
}
printf("\n");
}
return 0;
}