【Java算法】团体程序设计天梯赛L2-049 鱼与熊掌

文章讲述了如何使用Java编程解决一个关于给定物品拥有关系的问题,统计在面对多个物品种类时,有多少人能同时拥有特定的两个物品。通过维护每个人拥有的物品id列表并统计重复id来计算兼容人数。
摘要由CSDN通过智能技术生成

题目描述

yu.jpg

《孟子 · 告子上》有名言:“鱼,我所欲也,熊掌,亦我所欲也;二者不可得兼,舍鱼而取熊掌者也。”但这世界上还是有一些人可以做到鱼与熊掌兼得的。
给定 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 快速输入输出对象
}

最后附上代码运行时间

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值