首页 > 试题广场 >

三角谜题

[编程题]三角谜题
  • 热度指数:2189 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}对于给定的 n 种长度的棍子,第 i 种棍子的长度为 l_i ,有 a_i 根。从中任选三根,能组成的等腰三角形的面积最大值为多少?
\hspace{15pt}如果无法组成等腰三角形,则直接输出 -1

输入描述:
\hspace{15pt}每个测试文件均包含多组测试数据。第一行输入一个整数 T\left(1\leqq T\leqq 10^6 \right) 代表数据组数,每组测试数据描述如下:

\hspace{15pt}第一行输入一个整数 n \left( 1\leqq n \leqq 10^6 \right) 代表棍子的种类。
\hspace{15pt}此后 n 行,第 i 行输入两个整数 l_i, a_i \left(1 \leqq l_i, a_i \leqq 10^9 \right) 代表第 i 种棍子的长度和数量。

\hspace{15pt}除此之外,保证单个测试文件的 n 之和不超过 10^6


输出描述:
\hspace{15pt}在一行上输出一个实数,代表组成的最大等腰三角形的面积。如果无法组成等腰三角形,则直接输出 -1

\hspace{15pt}由于实数的计算存在误差,当误差的量级不超过 10^{-6} 时,您的答案都将被接受。具体来说,设您的答案为 a ,标准答案为 b ,当且仅当 \frac{|a-b|}{\max(1,|b|)}\leqq 10^{-6} 时,您的答案将被接受。
示例1

输入

2
3
3 3
2 1
3 1
2
1 2
12 1

输出

3.89711431702997391060
-1

说明

\hspace{15pt}对于第一组测试数据,可以构造 2 为底、3 为腰的三角形,面积 \approx 2.83 ;也可以构造 3 为底、3 为腰的三角形,面积 \approx 3.90 。显然,后者更大。

备注:
\hspace{15pt}本题数据量较大,我们建议您使用较快的读入方式。
解题思路:
1. 按照长度逆序排序,key:木棍长度,value:数量
2. 遍历value集合,找到第一个数量大于1的木棍 i 作为腰
3. 从0开始遍历key,一直到第二步的 i+1 个,找到第一个符合等腰三角形的组合,就是最大值
代码参考如下:(Math.sqrt方法精度只能到15或16,本题精确到了20,于是自定义了sqrt方法)
public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int total = in.nextInt();
        BigDecimal[] result = new BigDecimal[total];
        for (int i = 0; i < total; i++) {
            int typeCount = in.nextInt();
            int[][] lenAndNum = new int[typeCount][2];
            for (int j = 0; j < typeCount; j++) {
                lenAndNum[j][0] = in.nextInt();
                lenAndNum[j][1] = in.nextInt();
            }
            result[i] = getResult(lenAndNum);
        }
        for (BigDecimal d : result) {
            System.out.println(d);
        }
    }

    public static BigDecimal getResult(int[][] lenAndNum) {
        Map<BigDecimal, Integer> map = new LinkedHashMap<>();
        for (int i = 0; i < lenAndNum.length; i++) {
            BigDecimal len  = BigDecimal.valueOf(lenAndNum[i][0]);
            int num = lenAndNum[i][1];
            if (map.containsKey(len)) {
                map.put(len, map.get(len) + num);
            } else {
                map.put(len, num);
            }
        }
        map = map.entrySet().stream().sorted(Collections.reverseOrder(
                Map.Entry.comparingByKey())).collect(
                  Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (l1, l2)->l1,
                                   LinkedHashMap::new));
        List<BigDecimal> keyList = new LinkedList<>();
        List<Integer> valueList = new LinkedList<>();
        for (Map.Entry<BigDecimal, Integer> item : map.entrySet()) {
            keyList.add(item.getKey());
            valueList.add(item.getValue());
        }
        for (int i = 0; i < valueList.size(); i++) {
            Integer num = valueList.get(i);
            if (num >= 2) {
                for (int j = 0; j < Math.min(i + 1, valueList.size()); j++) {
                    if (num > 2) {
                        BigDecimal result = cal(keyList.get(i), keyList.get(j));
                        if (result.compareTo(BigDecimal.ZERO) > 0) {
                            return result;
                        }
                    }
                    if (num == 2 && i != j) {
                        BigDecimal result = cal(keyList.get(i), keyList.get(j));
                        if (result.compareTo(BigDecimal.ZERO) > 0) {
                            return result;
                        }
                    }
                }
            }
        }
        return BigDecimal.valueOf(-1);
    }

    public static BigDecimal cal(BigDecimal yao, BigDecimal di) {
        if (yao.add(yao).compareTo(di) < 0) {
            return new BigDecimal(-1);
        }
        BigDecimal halfDi = di.divide(BigDecimal.valueOf(2), 20, RoundingMode.HALF_UP);
        BigDecimal sqrtValue = yao.multiply(yao).subtract(halfDi.multiply(
                                   halfDi));
        BigDecimal gao = sqrt(sqrtValue, 20);
        return di.multiply(gao).divide(BigDecimal.valueOf(2), 20,
                                       RoundingMode.HALF_UP);
    }

    public static BigDecimal sqrt(BigDecimal num, int precision) {
        // 负数不能开平方
        if (num.compareTo(BigDecimal.ZERO) < 0) {
            throw new ArithmeticException("不能对负数开平方");
        }
        MathContext context = new MathContext(precision, RoundingMode.HALF_UP);
        BigDecimal guess = num.divide(BigDecimal.valueOf(2), context);
        BigDecimal tolerance = BigDecimal.ONE.scaleByPowerOfTen(-precision);
        while (true) {
            BigDecimal nextGuess = guess.add(num.divide(guess,
                                             context)).divide(BigDecimal.valueOf(2), context);
            if (nextGuess.subtract(guess).abs().compareTo(tolerance) <= 0) {
                return nextGuess;
            }
            guess = nextGuess;
        }
    }


发表于 2025-03-22 16:24:10 回复(0)