**
赛码网算法 军训队列
题目描述
某大学开学进行军训队列训练,将学生从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列剩下的依次向前靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的依次向前靠拢,继续从头开始进行一至二报数。。。以后每次从头开始轮流进行一至二报数、一至三报数直到剩下的人数不超过三人为止。
link.
心路历程
第一次做这种传统oj。哇刚看到这道题,结合题目和输入输出,整个都给看蒙了,不知道输入输出和题目有啥关系,感觉赛码真的和leetcode,牛客差好多,题目描述一大堆。。。。看了真的是半天(绝不虚假的时间)也没看太懂,最后还是自己动手在纸上比划终于读懂题意了。
题目分析
样例输入
2
20
40
样例输入中的2代表两组学生,接下来的20,40分别代表第一组,第二组学生人数。以第一组20个学生为例,
第一次报数(报到二的出列)后剩下的学生的原始编号为:1,3,5,7,…,17,19
第二次报数(报到三的出列)后剩下的学生的原始编号为:
1,3,7,9,13,15,19
第三次报数(报到二的出列)后剩下的学生的原始编号为:
1,7,13,19
第四次报数(报到三的出列)后剩下的学生的原始编号为:
1,7,19
此时剩下的人数不超过三了,算法结束可以输出了
思路
首先取出输入的第一行整数N,然后对接下来的N条输入分别进行处理:分别根据每一行中的整数n创建相应大小的int数组,将学生编号放入该数组中,再依次循环对数组进行二次出队,三次出队的操作。注意使用到了clone()方法。
代码
膜一膜某大神的简洁代码,加了自己的注释理解
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt(); //输入学生的组数
for (int i = 0; i < N; i++) { //读完输入的学生的组数
int n = scanner.nextInt();//每组中的学生数
int k = n; //用k来记录每次变化后的学生数
int[] a = new int[n]; //创建学生数大小的int数组放置学生编号
// 将学生编号放入数组中
for (int j = 0; j < a.length; j++) {
a[j] = j + 1;
}
while (k > 3) {//一次报数后剩下的人数是否小于3
k = k - k / 2; //报道2出队之后的学生数
a = oq(k, a, 2);
if(k>3){ //如果此时人数还是大雨3,就让剩下的报到三的出队
k = k - k / 3; //报道3出队之后的学生数
a= oq(k, a, 3);
}else{
break;
}
}
for(int c = 0; c < a.length; c++){
System.out.print(a[c] + " ");
}
}
}
private static int[] oq(int k, int[] a, int d) {//d取值为2或者3
int[] b = a.clone(); //kelong数组
a = new int[k]; //开辟k空间大小的数组a
for (int t = 1, q = 0; t <= b.length; t++) {
// ??
if (t % d != 0) {
a[q] = b[t-1];
q++;
}
}
return a;
}
}