PAT (Advanced Level) Practice1003 Emergency (25 分)(Java实现)

本文介绍了一种用于救援队在紧急情况下快速响应并集结最大人力的路径规划算法。该算法基于Dijkstra算法改进,能够在考虑最短路径的同时,计算出能够集结最多救援队伍的路径数目及最大救援队伍数量。

Problem Description

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N(≤500)N (≤500)N(500) - the number of cities (and the cities are numbered from 000 to N−1)N−1)N1), M - the number of roads, C​1C​_1C1​​ and C2C_2C2​​ - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c1c_1c1, c2c_2c2​​ and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1C_​1C1​​ to C​2C_​2C2
​​

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1C_1C1​​ and C​2C_​2C2​​ , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

代码示例(Java实现)

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * @create-date 2019-07-27 19:01
 */
public class Main {

    // ====================================================
    // 测试用例一
    //    5 6 0 4
    //    1 2 1 5 3
    //    0 1 1
    //    0 2 2
    //    0 3 1
    //    1 2 1
    //    2 4 1
    //    3 4 1
    // 测试用例二
    //    4 5 0 3
    //    1 2 3 4
    //    0 1 1
    //    0 2 1
    //    1 3 1
    //    2 3 1
    //    0 3 2
    // ====================================================
    
    public static void main(String[] args) throws IOException {
        // 初始化输入
        Reader.init(System.in);
        // 获取到城市的数量
        int cities = Reader.nextInt();
        // 获取路的条数
        int roads = Reader.nextInt();
        // 获取到起始城市下标
        int startIndex = Reader.nextInt();
        // 获取到终点城市下标
        int destinationIndex = Reader.nextInt();
        // 存储每个城市的治疗小组
        int[] citiesPerson = new int[cities];
        // 创建一个 cities * cities 的数组,存储城市与城市之间的道路的联系
        int[][] map = new int[cities][cities];

        // 厨师换城市之间的关系,
        for (int[] m : map) {
            Arrays.fill(m, 0XFFFF);
        }

        // 获取城市人数
        for (int i = 0; i < cities; i++) {
            citiesPerson[i] = Reader.nextInt();
        }

        // 是一个无向图
        for (int i = 0; i < roads; i++) {
            int start = Reader.nextInt();
            int end = Reader.nextInt();
            int distance = Reader.nextInt();
            // 是一个无向图
            map[start][end] = distance;
            map[end][start] = distance;
        }

        // 通过 dijkstra 算法获取到结果
        Vector<Vector<Integer>> paths = dijkstra(map, startIndex);

        {
            // 获取到路径条数
            int count = count(paths, destinationIndex);
            // 获取到最多的治疗小组
            int maxGroupCount = citiesPerson[destinationIndex] + filter(paths, destinationIndex, citiesPerson);
            System.out.println(count + " " + maxGroupCount);
        }

    }

    /**
     * 获取不同路径的条数
     *
     * @param paths 路径
     * @param end   终点下标
     * @return      道路的条数
     */
    public static int count(Vector<Vector<Integer>> paths, int end) {
        int count = 0;
        Vector<Integer> vector = paths.get(end);
        if (vector.isEmpty()) {
            count = 1;
        }
        for (int temp : vector) {
            count += count(paths, temp);
        }
        return count;
    }

    /**
     * 过滤出想要的结果
     *
     * @param paths         路径向量
     * @param end           终点
     * @param citiesPerson  每个城市的人数
     * @return              返回最大的结果
     */
    private static int filter(Vector<Vector<Integer>> paths, int end, int[] citiesPerson) {
        int max = 0;
        // 取出 end 对应的向量
        Vector<Integer> vector = paths.get(end);
        for (int temp : vector) {
            max = Math.max(max, citiesPerson[temp] + filter(paths, temp, citiesPerson));
        }
        return max;
    }

    /**
     * 利用 dijkstra 算法,求出两点之间最近的距离,并且求出路径
     *
     * @param map       地图数据
     * @param start     起点下标
     */
    private static Vector<Vector<Integer>> dijkstra(int[][] map, int start) {
        // 创建一个访问标记数组
        boolean[] visited = new boolean[map.length];
        // 创建一个路径数组
        Vector<Vector<Integer>> paths = new Vector<>();
        // 创建一个 start 到其他顶点的最短距离数组
        int[] distance = new int[map.length];
        // 初始化数据
        {
            // 源点到任意一个点所经过的点的上一个点的下标
            // 标记源点访问过
            visited[start] = true;
            // 初始化一下源点到其他点的距离
            for (int i = 0; i < map.length; i++) {
                if (map[start][i] != 0XFFFF) {
                    Vector<Integer> vector = new Vector<>();
                    vector.add(start);
                    paths.add(vector);
                } else {
                    paths.add(new Vector<>());
                }
                distance[i] = map[start][i];
            }
        }
        // 由于已经初始化第一次的循环,所以从下一个开始即可,开始计算
        for (int i = (start + 1) % map.length; i != start;  i = (i + 1) % map.length) {
            // 找到当前 distance 数组中最短的距离,并且不为 0
            int minDistance = 0XFFFF, minIndex = -1;
            for (int j = 0; j < distance.length; j++) {
                // 找到没有访问国并且边权值最小的那条边
                if (!visited[j] && distance[j] < minDistance) {
                    minDistance = distance[j];
                    minIndex = j;
                }
            }

            // 标记 minIndex 访问过
            visited[minIndex] = true;
            // 修正最短距离
            for (int j = 0; j < distance.length; j++) {
                // 如果能多经过一个点,就多经过一个点,所以相等的情况也改变的它的路径,这就是这道题的一个难点,
                // 因为从起点到目标顶点的最短距离可以有多个,经过的点越多,聚集的治疗团队就越多
                if (!visited[j]) {
                    if (distance[minIndex] + map[minIndex][j] < distance[j]) {
                        distance[j] = distance[minIndex] + map[minIndex][j];
                        // 如果出现更优的方案,需要删除之前的最优方案,然后再添加最新的最优的方案
                        paths.get(j).clear();
                        paths.get(j).add(minIndex);
                    } else if (distance[minIndex] + map[minIndex][j] == distance[j]) {
                        // 如果出现相同的方案,追加新的方案
                        paths.get(j).add(minIndex);
                    }
                }
            }
        }
        return paths;
    }


}

class Reader {

    static BufferedReader reader;
    private static StringTokenizer tokenizer;

    /** call this method to initialize reader for InputStream */
    public static void init(InputStream input) {
        reader = new BufferedReader(new InputStreamReader(input));
        tokenizer = new StringTokenizer("");
    }

    public static String nextLine() throws IOException {
        return reader.readLine();
    }

    /** get next word */
    public static String next() throws IOException {
        while (!tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(reader.readLine());
        }
        return tokenizer.nextToken();
    }

    public static int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static double nextDouble() throws IOException {
        return Double.parseDouble(next());
    }

}

### PAT 基本级别练习的相关资料 PAT(Programming Ability Test)是一项针对编程能力的标准化考试,其基本级别主要考察考生的基础编程技能和逻辑思维能力。以下是关于 PAT 基本级别的练习题目及相关解决方案的内容。 #### 题目PAT 基本级别的题目通常为以下几个类别: 1. **字符串处理**:涉及字符串的操作,如反转、查找子串等。 2. **数组操作**:包括数组排序、去重、统计等问题。 3. **简单算法实现**:如计算阶乘、判断素数等基础算法。 4. **输入输出格式化**:要求按照特定格式读取数据并输出结果。 以下是一些典型的 PAT 基本级别练习题及其解决思路: --- #### 示例题目 1: 字符串反转 **描述**: 输入一个字符串,将其逆序输出。 **解法**: 可以通过 Python 中的切片功能轻松实现字符串反转。 ```python def reverse_string(s): return s[::-1] # 测试用例 input_str = input() print(reverse_string(input_str)) ``` 此代码利用了 Python 切片语法 `s[start:end:step]`,其中步长为 `-1` 表示反向遍历字符串[^4]。 --- #### 示例题目 2: 数组求和 **描述**: 给定一组整数,求数组中所有元素的总和。 **解法**: 通过循环累加或者内置函数 `sum()` 实现数组求和。 ```python def array_sum(arr): return sum(arr) # 测试用例 numbers = list(map(int, input().split())) print(array_sum(numbers)) ``` 上述代码中,`map()` 函数用于将输入转换为整型列表,而 `sum()` 是 Python 的内置函数,能够高效完成求和任务[^5]。 --- #### 示例题目 3: 计算阶乘 **描述**: 输入一个正整数 \( n \),输出它的阶乘 \( n! \)。 **解法**: 使用递归或迭代方式均可实现阶乘计算。 ```python def factorial(n): if n == 0 or n == 1: return 1 result = 1 for i in range(2, n + 1): result *= i return result # 测试用例 n = int(input()) print(factorial(n)) ``` 该程序采用了迭代方法避免栈溢出的风险,在实际应用中更为稳健[^6]。 --- #### 示例题目 4: 判断素数 **描述**: 输入一个正整数 \( m \),判断它是否为素数。 **解法**: 素数是指仅能被 1 和自身整除的大于 1 的自然数。可通过试除法验证。 ```python import math def is_prime(m): if m <= 1: return False sqrt_m = int(math.sqrt(m)) + 1 for i in range(2, sqrt_m): if m % i == 0: return False return True # 测试用例 m = int(input()) if is_prime(m): print("Yes") else: print("No") ``` 在此代码片段中,引入了平方根优化技术以减少不必要的运算次数[^7]。 --- ### 总结 以上展示了几个常见的 PAT 基础级问题以及对应的解决方案。这些例子涵盖了字符串操作、数组处理、数学计算等多个方面,有助于初学者熟悉 PAT 考试的形式与难度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值