目录
题目描述
小蓝有 N 个小球,编号 1 至 N。其中 N − 1 是正品,重量相同;有 1 个是次品,重量比正品轻。
为了找出次品,小蓝已经用天平进行了 M 次称重,并且记录下来每次两边放的小球编号,和称重结果。
请你根据记录,判断还剩下几个小球有次品的嫌疑。
输入格式
第一行包含 2 个整数 N 和 M。
以下包含 M 次称重记录,每个记录占 4 行。
第一行是一个整数 K,表示天平两边各放了 K 个小球。
第二行包含 K 个整数,代表放在天平左边的小球编号。
第三行包含 K 个整数,代表放在天平右边的小球编号。
第四行是一个字符,为 ‘>’, ‘<’, ‘=’ 之一。‘>’ 代表左边比右边重,‘<’ 代表左边比右边轻,‘=’ 代表两边重量相等。
在一次称重中保证每个小球最多出现 1 次。
输出格式
输出一个整数,代表答案。
样例输入
10 2
3
1 2 3
4 5 6
<
2
3 7
8 9
=
样例输出
2
提示
{1, 2, 3} < {4, 5, 6} 能判断出次品在 {1, 2, 3} 之中。
{3, 7} = {8, 9} 能判断出 3 不可能是次品。
所以只剩下 {1, 2} 可能是次品。
对于 40% 的数据,1 ≤ N ≤ 106 ;
对于 100% 的数据,1 ≤ N ≤ 109 , 1 ≤ M ≤ 105 , 参与 M 次称重的小球总数 ≤ 106 .
原题链接
题目 2720: 蓝桥杯2022年第十三届决赛真题-小球称重https://www.dotcpp.com/oj/problem2720.html
代码思路
代码中调用HashSet集合的函数 介绍
isEmpty():用于判断HashSet是否为空.如果HashSet为空,则返回True,否则返回False.
contains():用于判断HashSet是否包含某个元素.如果包含指定的元素,则返回true,否则返回false.
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
// HashSet可以帮助我们去重,且在查询和删除时的效率高,符合我们的需求,所以使用
// s1存的是有嫌疑的小球
// s2存的是没有嫌疑的小球
Set<Integer> s1 = new HashSet<Integer>();
Set<Integer> s2 = new HashSet<Integer>();
// m次循环
while (m-- > 0) {
// s3起到一个过渡作用,将s1里没有解除嫌疑的小球存入s3,然后s3再赋值给s1,搞完一轮后然后再初始化
Set<Integer> s3 = new HashSet<Integer>();
int sl = scanner.nextInt();
// ArrayList集合是在查询元素时速度很快,但在增加或删除元素时效率较低
// 以下代码明显查询元素较多,所以最好使用ArrayList集合
List<Integer> a = new ArrayList<Integer>();
List<Integer> b = new ArrayList<Integer>();
// 向a和b对象里添加小球
for (int i = 0; i < sl; i++) {
a.add(scanner.nextInt());
}
for (int i = 0; i < sl; i++) {
b.add(scanner.nextInt());
}
// 记录天平的称重结果 <,>还是=
String string = scanner.next();
if (string.equals(">")) {
// isEmpty()函数 是容器为空的化返回true
if (s1.isEmpty()) {
// s1为空的化,将有嫌疑的小球存入
for (Integer p : b) {
// contains(元素n)函数 是有这个元素n,则返回true
// 如果s2里没有,s1再存入(是为了避免没有嫌疑的小球存入)
if (!s2.contains(p)) {
s1.add(p);
}
}
} else {
// s1不为空,将有嫌疑的小球存入
for (Integer integer : b) {
// contains(元素n)函数 是有这个元素n返回true
// 如果s1里有这个小球,s3就存入(因为次品只有一个,那么缩小 嫌疑小球的范围 并存入s3中)
if (s1.contains(integer)) {
s3.add(integer);
} else {
// s1里没有的化,s2就存入(扩大没有嫌疑的小球,让判断小球有无嫌疑更加准确)
s2.add(integer);
}
}
// 将更加准确的嫌疑小球 赋值给s1
s1 = s3;
}
} else if (string.equals("<")) {
if (s1.isEmpty()) {
// s1为空的化,将有嫌疑的小球存入
for (Integer p : a) {
// contains(元素n)函数 是有这个元素n,则返回true
// 如果s2里没有,s1再存入(是为了避免没有嫌疑的小球存入)
if (!s2.contains(p)) {
s1.add(p);
}
}
} else {
// s1不为空,将有嫌疑的小球存入
for (Integer integer : a) {
// contains(元素n)函数 是有这个元素n返回true
// 如果s1里有这个小球,s3就存入(因为次品只有一个,那么缩小 嫌疑小球的范围 并存入s3中)
if (s1.contains(integer)) {
s3.add(integer);
} else {
// s1里没有的化,s2就存入(扩大没有嫌疑的小球,让判断小球有无嫌疑更加准确)
s2.add(integer);
}
}
// 将更加准确的嫌疑小球 赋值给s1
s1 = s3;
}
} else {
// 天平的称重结果要是等于的化,说明两边的小球都没有嫌疑(因为次品小球只有一个,所以不可能 即有次品小球,又有两边还相等的情况)
// 所以s1要删除没有嫌疑的小球
// 所以s2要添加没有嫌疑的小球
for (Integer integer : b) {
s1.remove(integer);
s2.add(integer);
}
for (Integer integer : a) {
s1.remove(integer);
s2.add(integer);
}
}
}
if (s1.isEmpty()) {
// s1是空的话,则说明有嫌疑的小球没出现过,所以要用 (总数量-没有嫌疑的小球数量 结果是 有嫌疑的小球数量)
System.out.println(n - s2.size());
} else {
// s1不为空,则直接输出有嫌疑的小球数量
System.out.println(s1.size());
}
}
}