题目:某部队进行新兵队列训练,将新兵从1开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始1至2报数,凡报到2的出列,剩下的向小序号方向靠拢,再从头开始进行1至3报数,凡报到3的出列,剩下的向小序号方向靠拢,继续从头开始进行1至2报数,以后从头开始轮流进行1至2报数、1至3报数直到剩下的人数不超过三人为止。编写程序,输入数N为最开始的新兵人数(20 < N < 6000),输出剩下的新兵最初的编号。
输入样例:
21
输出样例:
1 7 19
来自编程小白(没错就是我)的想法:
- 因为N是变量,所以用new实现内存分配(讲真,学校网站用的在线编译器太老了,不过问题不大),支持新标准C++的可以直接int list[N]
- 根据题目中“像小序号靠拢”,说明每次有人出队列,第二次报数的时候,人们在队列中的位置会发生变化,但是最后还要输出人们的起始位置,所以我就想用一个结构体,存储起始位置和新位置。
- 如果用数组的话,可以让他们的位置编号和数组的索引相对应。
- 由2 可知需要一个函数来赋予他们新的位置,然后出队列的时候把新位置的值变成0,表示他出去了。
- 使用一个变量count来区分是1-3还是1-2
- 由于题目要求剩余人数不大于3个的时候停止,所以需要一个记录队列中有效人数的数字num
- 输出的时候注意最后一位没有空格
贴代码:
#include<iostream>
struct element {
int festnum;
int Newnum;
};
void renum(element* list, int N ) { //给他新的编号
int n = 1;
for (int i = 0; i < N; i++) {
if (list[i].Newnum != 0) {
list[i].Newnum = n;
n++;
}
}
}
void gout(element* list,int N,int count,int& num) {
for (int i = 0; i < N; i++) {
if (list[i].Newnum % count == 0 && list[i].Newnum != 0) {
list[i].Newnum = 0;
num--;
}
}
}
int main() {
int N;
element* list;
int count = 2;
std::cin >> N;
list = new element[N];
int num = N;
for (int i = 0; i < N; i++) {
list[i].festnum = i+1; //记录编号
list[i].Newnum = list[i].festnum;
} //删除完一次就重新给一个编号
while (num > 3) {
gout(list, N, count, num);
renum(list, N);
if (count == 2) count = 3;
else count = 2;
}
int x = 1;
for (int i = 0; i < N; i++) {
if (list[i].Newnum != 0&&x!=num) {
std::cout << list[i].festnum<<" ";
x++;
continue;
}
if (list[i].Newnum != 0 && x == num) {
std::cout << list[i].festnum;
break;
}
}
delete[] list;
}