求差集
【问题描述】
两个集合的差集定义如下:
集合A、B的差集,由所有属于A但不属于B的元素构成。
输入两个集合A、B,每个集合中元素都是自然数。求集合A、B的差集。
【输入形式】
从标准输入接收集合中的自然数元素,以空格分隔。-1表示输入结束。
其中,每个集合都不输入重复的元素。
【输出形式】
输出差运算后集合中的元素,以空格分隔。输出元素的顺序与原有集合A输入的顺序一致。
如果A、B的差集为空集,则不输出任何数值。
【样例输入】
2 8 3 4 -1
6 1 4 9 -1
【样例输出】
2 8 3
【样例说明】
从标准输入接收集合中的自然数元素,输出集合A、B的差集。
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读入集合A
HashSet<String> setA = new HashSet<>(Arrays.asList(sc.nextLine().split(" ")));
// 读入集合B
HashSet<String> setB = new HashSet<>(Arrays.asList(sc.nextLine().split(" ")));
// 求差集
setA.removeAll(setB);
// 输出结果
if (setA.size() > 0) {
String[] diff = setA.toArray(new String[0]);
Arrays.sort(diff);
System.out.println(String.join(" ", diff));
}
}
}
CCF 201712-2 游戏
【问题描述】
有n个小朋友围成一圈玩游戏,小朋友从1至n编号,2号小朋友坐在1号小朋友的顺时针方向,
3号小朋友坐在2号小朋友的顺时针方向,……,1号小朋友坐在n号小朋友的顺时针方向。
游戏开始,从1号小朋友开始顺时针报数,接下来每个小朋友的报数是上一个小朋友报的数加1。
若一个小朋友报的数为k的倍数或其末位数(即数的个位)为k,则该小朋友被淘汰出局,不再参加以后的报数。
当游戏中只剩下一个小朋友时,该小朋友获胜。
例如,当n=5, k=2时:
1号小朋友报数1;
2号小朋友报数2淘汰;
3号小朋友报数3;
4号小朋友报数4淘汰;
5号小朋友报数5;
1号小朋友报数6淘汰;
3号小朋友报数7;
5号小朋友报数8淘汰;
3号小朋友获胜。
给定n和k,请问最后获胜的小朋友编号为多少?
【输入形式】
输入一行,包括两个整数n和k,意义如题目所述。
【输出形式】
输出一行,包含一个整数,表示获胜的小朋友编号。
【样例输入】
5 2
【样例输出】
3
【样例输入】
7 3
【样例输出】
4
【评分标准】
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 9。
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //输入孩子数量n
int k = sc.nextInt(); //输入喊号数k
Queue<Integer> children = new LinkedList<Integer>(); //创建队列存储孩子编号
for(int i=1;i<=n;i++) {
children.offer(i); //将孩子编号添加到队列中
}
for(int j=1;children.size()!=1;j++) { //循环直到仅剩一个孩子
int temp = children.poll(); //从队列头部删除当前孩子
if(!(j%k==0 || j%10==k)) { //如果该孩子不需要删除,则重新添加到队列尾部
children.offer(temp);
}
}
sc.close();
System.out.println(children.poll()); //输出最后剩下的孩子编号
}
}
CCF 201609-2 火车购票
【问题描述】
请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配。
假设一节车厢有20排、每一排5个座位。为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10号,依次类推,第20排是96到100号。
购票时,一个人可能购一张或多张票,最多不超过5张。如果这几张票可以安排在同一排编号相邻的座位,则应该安排在编号最小的相邻座位。否则应该安排在编号最小的几个空座位中(不考虑是否相邻)。
假设初始时车票全部未被购买,现在给了一些购票指令,请你处理这些指令。
【输入形式】
输入的第一行包含一个整数n,表示购票指令的数量。
第二行包含n个整数,每个整数p在1到5之间,表示要购入的票数,相邻的两个数之间使用一个空格分隔。
【输出形式】
输出n行,每行对应一条指令的处理结果。
对于购票指令p,输出p张车票的编号,按从小到大排序。
【样例输入】
4
2 5 4 2
【样例输出】
1 2
6 7 8 9 10
11 12 13 14
3 4
【样例说明】
1) 购2张票,得到座位1、2。
2) 购5张票,得到座位6至10。
3) 购4张票,得到座位11至14。
4) 购2张票,得到座位3、4。
【评分标准】
评测用例规模与约定
对于所有评测用例,1 ≤ n ≤ 100,所有购票数量之和不超过100。
import java.util.Scanner;
import java.util.TreeSet;
import java.util.Vector;
public class Main {
// 存储每个座位还剩余的票数
static int seat[] = new int[20];
// 存储所有分配结果的集合
static Vector<TreeSet<Integer>> result = new Vector<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 初始化每个座位可容纳的票数
for (int i = 0; i < 20; i++)
seat[i] = 5;
// 对每个购票请求进行处理
for (int i = 0; i < n; i++) {
distr(sc.nextInt());
}
// 输出所有分配结果
for (TreeSet<Integer> a : result) {
for (int b : a)
System.out.print(b + " ");
System.out.println();
}
}
/**
* 分配指定数量的票
*
* @param tickets 待分配的票数量
*/
public static void distr(int tickets) {
TreeSet<Integer> ts = new TreeSet<>();
for (int i = 0; i < 20; i++) {
if (seat[i] >= tickets) {
// 如果该座位能够完全容纳这些票,则直接安排在该座位上
for (int t = 0; t < tickets; t++)
ts.add(5 * (i + 1) - seat[i] + t + 1);
// 更新座位剩余的票数
seat[i] -= tickets;
// 添加分配结果到集合中并返回
result.add(ts);
return;
}
}
// 如果没有单个座位能够完全容纳这些票,则进行多个座位的组合分配
for (int i = 0; i < 20; i++) {
if (seat[i] > 0) {
int min = seat[i] > tickets ? tickets : seat[i];
for (int t = 0; t < min; t++)
ts.add(5 * (i + 1) - seat[i] + 1 + t);
seat[i] -= min;
tickets -= min;
if (tickets == 0) {
result.add(ts);
return;
}
}
}
}
}
CCF 201703-2 学生排队
【问题描述】
体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。
例如,下面给出了一组移动的例子,例子中学生的人数为8人。
0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7, 8;
1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 3, 6, 7, 8;
2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 8, 3, 6, 7;
3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 3, 5, 8, 6, 7。
小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少?
请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,
如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。
在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。
【输入形式】
输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。
第二行包含一个整数m,表示调整的次数。
接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。
【输出形式】
输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,
表示最终从前向后所有学生的学号。
【样例输入】
8
3
3 2
8 -3
3 -2
【样例输出】
1 2 4 3 5 8 6 7
【评分标准】
对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 输入数组长度和操作次数
int n = in.nextInt(), m = in.nextInt();
// 初始化链表 a,存储数字 1 到 n
List<Integer> a = new LinkedList<>();
for (int i = 1; i <= n; i++) {
a.add(i);
}
// 针对每个操作进行处理
for (int i = 0; i < m; i++) {
// 输入要移动的数字以及移动的步数
int num = in.nextInt(), move = in.nextInt();
// 获取要移动的数字的下标 index
int index = a.indexOf(num);
// 将该数字从链表中移除
a.remove(index);
// 将该数字插入到移动后的位置
a.add(index + move, num);
}
// 输出最终结果
for (int val : a) {
System.out.print(val + " ");
}
}
}