6.4
某部队进行新兵队列训练,将新兵从1开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始1至2报数,凡报到2的出列,剩下的向小序号方向靠拢,再从头开始进行1至3报数,凡报到3的出列,剩下的向小序号方向靠拢,继续从头开始进行1至2报数,以后从头开始轮流进行1至2报数、1至3报数直到剩下的人数不超过三人为止。编写程序,输入数N为最开始的新兵人数(20 < N < 6000),输出剩下的新兵最初的编号。
#include<stdio.h>//bug容易泛滥的一道题目,for循环体很需要严谨的数学思维:如何转换,何时停止循环
int main()
{
int n,i,a[6000];
scanf("%d", &n);
for (i = 0; i < n; i++)
a[i] = i + 1;//定义队列数
while (n > 3)
{
for (i = 0; 2 * i < n; i++)
a[i] = a[2 * i];
n = i;//报号为2的出列
while (n > 3)//n<=3时停止循环
{
if ((n + 2) % 3 != 0)/*case1:报号为3者出列后,末尾有单独两项或无项;
例如输入n=9,报号为2的出列得到1 3 5 7 9,报号为3的出列(去除5),5后面有单独两项7和9
例如输入n=11,报号为2的出列得到1 3 5 7 9 11,报号为3的出列(去除5 11),11后面无项*/
{
for (i = 0; ((3 * i) / 2 + 1) < n; i = i + 2)
a[i] = a[(3 * i) / 2], a[i + 1] = a[(3 * i) / 2 + 1];
n = i;
}
else/*case2:报号为3者出列后,末尾只有单独一项;
例如输入n=7,报号为2的出列得到1 3 5 7,报号为3的出列(去除5),5后面只有单独一项7*/
{
for (i = 0; ((3 * i) / 2 + 1) < n; i = i + 2)
a[i] = a[(3 * i) / 2], a[i + 1] = a[(3 * i) / 2 + 1];
a[i] = a[(3 * i) / 2];
n = i+1;
}
break;//易遗漏这个break
}
}
for (i = 0; i < n; i++)//输出最后的队列
{
printf("%d", a[i]);
if (i != n - 1)
printf(" ");//空格输出控制
}
system("pause");
return 0;
}