题目描述
《孟子 · 告子上》有名言:“鱼,我所欲也,熊掌,亦我所欲也;二者不可得兼,舍鱼而取熊掌者也。”但这世界上还是有一些人可以做到鱼与熊掌兼得的。
给定 n 个人对 m 种物品的拥有关系。对其中任意一对物品种类(例如“鱼与熊掌”),请你统计有多少人能够兼得?
输入格式:
输入首先在第一行给出 2 个正整数,分别是:n(≤105)为总人数(所有人从 1 到 n 编号)、m(2≤m≤105)为物品种类的总数(所有物品种类从 1 到 m 编号)。
随后 n 行,第 i 行(1≤i≤n)给出编号为 i 的人所拥有的物品种类清单,格式为:
K M[1] M[2] ... M[K]
其中 K
(≤103)是该人拥有的物品种类数量,后面的 M[*]
是物品种类的编号。题目保证每个人的物品种类清单中都没有重复给出的种类。
最后是查询信息:首先在一行中给出查询总量 Q(≤100),随后 Q 行,每行给出一对物品种类编号,其间以空格分隔。题目保证物品种类编号都是合法存在的。
输出格式:
对每一次查询,在一行中输出两种物品兼得的人数。
输入样例:
4 8
3 4 1 8
4 7 1 8 4
5 6 5 1 2 3
4 3 2 4 8
3
2 3
7 6
8 4
输出样例:
2
0
3
代码长度限制 16 KB
Java (javac)
时间限制 2000 ms
内存限制 256 MB
其他编译器
时间限制 400 ms
内存限制 64 MB
栈限制 8192 KB
解题思路
这题Java给2000ms惊到我了(吐槽一下JVM刚启动太慢了)
总体思路就是维护拥有该物品的人的id的List(不可以直接开int[m][n],会超内存),然后拿到两个物品的id list统计重复数量。
统计重复数量可以使用一个boolean[] temp,首先遍历第一个物品id的List,使用id当做索引给temp赋值true,然后遍历第二个物品id的List,拿id当做索引检查temp[id]是不是为true,为true则说明是重复的id,计数+1。
实现代码
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws Exception {
int n = readInt();
int m = readInt();
// 维护每一个拥有该种类物品的人的id List
ArrayList<Integer>[] map = new ArrayList[m + 1];
for (int i = 1; i <= n; i++) {
int k = readInt();
for (int j = 0; j < k; j++) {
int id = readInt();
ArrayList<Integer> s = map[id];
if (s == null) {
ArrayList<Integer> list = new ArrayList<>();
list.add(i);
map[id] = list;
} else {
s.add(i);
}
}
}
// q次查询
boolean[] temp = new boolean[n+1];
int q = readInt();
for (int i = 0; i < q; i++) {
int id1 = readInt();
int id2 = readInt();
int count = 0;
Arrays.fill(temp, false);
ArrayList<Integer> s1 = map[id1];
ArrayList<Integer> s2 = map[id2];
// 创建map
for (Integer num : s1) {
temp[num] = true;
}
for (Integer num : s2) {
if (temp[num]) {
count++;
}
}
bw.write(Integer.toString(count));
bw.newLine();
}
bw.flush();
}
// region 设置系统输入流为stdin.txt文件,输出流为stdout.txt
static {
// try {
// System.setIn(new FileInputStream("stdin.txt"));
// System.setOut(new PrintStream("stdout.txt"));
// } catch (FileNotFoundException e) {
// throw new RuntimeException(e);
// }
}
// endregion 设置系统输入流为stdin.txt,输出流为stdout.txt
// region 快速输入输出对象
/**
* 输入流
*/
public static final Scanner sc = new Scanner(System.in);
public static final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static final StreamTokenizer st = new StreamTokenizer(br);
public static final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
private static int readInt() {
try {
st.nextToken();
return (int) st.nval;
} catch (Exception ignored) {
}
return -1;
}
private static double readDouble() {
try {
st.nextToken();
return st.nval;
} catch (Exception ignored) {
}
return -1;
}
private static String readString() {
try {
st.nextToken();
return st.sval;
} catch (Exception ignored) {
}
return "";
}
/**
* 配置st读取数字字符串
*/
private static void parseLongNumber() {
st.ordinaryChars('0', '9');
st.wordChars('0', '9');
}
private static long readLong() {
try {
st.nextToken();
return Long.parseLong(st.sval);
} catch (Exception ignored) {
}
return -1;
}
// endregion end 快速输入输出对象
}
最后附上代码运行时间