L2-001 城市间紧急救援(Dijkstra + 打印路径 + 记录最短路条数)

思路:

        这道题目考察的点很多,首先我们要求起点S到终点D最短路,可以使用Dijkstra算法,即bfs + 贪心,由题目没有给出M的范围,所以我们无法判断图是稠密图还是稀疏图来决定是否使用优先队列来取得更好的时间复杂度,我采用的是优先队列。

        其次,我们需要一个 pre[] 数组来记录最短路上结点的上一个结点,来辅助我们打印最短路径。

        最后,我们还要使用 dp[i] 数组记录以i为终点最短路的条数,当我们找到了一条更短的路径时,令 dp[j] = dp[i]。如果没有找到了一个与当前最短路长度相同的路径,令 dp[j] += dp[i]。

AC 代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 600,INF = 0x3f3f3f3f;
struct edge {
	int to,w;
	edge(int a,int b) {
		to = a;
		w = b
### L2-001 城市间紧急救援 Java 实现 以下是基于 Dijkstra 算法的一个实现方案,用于解决城市间路径问题并大化沿途召集的救援量。 #### 数据结构设计 为了高效处理输入据,可以采用邻接表来表示图中的节点及其边权重。同时,定义一个优先级队列(PriorityQueue),按照当前距离和已召集的救援进行排序[^1]。 ```java import java.util.*; class State implements Comparable<State> { int city; // 当前所在城市编号 long dist; // 到达该城市的总路程 int rescueNums; // 已经召集到的救援队总 public State(int city, long dist, int rescueNums) { this.city = city; this.dist = dist; this.rescueNums = rescueNums; } @Override public int compareTo(State other) { if (this.dist != other.dist) return Long.compare(this.dist, other.dist); return Integer.compare(other.rescueNums, this.rescueNums); // 更多救援队优先 } } ``` 上述 `State` 类封装了状态信息,并通过重写 `compareTo` 方法实现了优先级比较逻辑:如果两个状态的距离不同,则按较小距离优先;如果距离相同,则按较大救援优先。 #### 主算法实现 利用改进版的 Dijkstra 算法,在遍历过程中记录到达每个城市的小距离以及大可召集的救援目。 ```java public class EmergencyRescue { static final int INF = Integer.MAX_VALUE; public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); // 城市量 N int m = scanner.nextInt(); // 道路量 M int c1 = scanner.nextInt() - 1;// 起始城市 C1 (转换为索引) int c2 = scanner.nextInt() - 1;// 终点城市 C2 (转换为索引) List<List<Edge>> graph = buildGraph(n, m, scanner); int[] rescues = readRescues(scanner, n); Result result = dijkstra(graph, rescues, c1, c2); System.out.println(result.maxRescue + " " + result.waysCount); } private static List<List<Edge>> buildGraph(int n, int m, Scanner scanner) { List<List<Edge>> graph = new ArrayList<>(); for (int i = 0; i < n; ++i) graph.add(new ArrayList<>()); while (m-- > 0) { int u = scanner.nextInt() - 1; int v = scanner.nextInt() - 1; int w = scanner.nextInt(); graph.get(u).add(new Edge(v, w)); graph.get(v).add(new Edge(u, w)); // 双向道路 } return graph; } private static int[] readRescues(Scanner scanner, int n) { int[] rescues = new int[n]; for (int i = 0; i < n; ++i) rescues[i] = scanner.nextInt(); return rescues; } private static Result dijkstra(List<List<Edge>> graph, int[] rescues, int startCity, int endCity) { PriorityQueue<State> pq = new PriorityQueue<>(); pq.offer(new State(startCity, 0, rescues[startCity])); long[] distances = new long[graph.size()]; Arrays.fill(distances, INF); distances[startCity] = 0; int[] maxRescues = new int[graph.size()]; maxRescues[startCity] = rescues[startCity]; int[] waysCounts = new int[graph.size()]; waysCounts[startCity] = 1; while (!pq.isEmpty()) { State current = pq.poll(); if (current.city == endCity) break; for (Edge edge : graph.get(current.city)) { int nextCity = edge.to; long distanceToNext = current.dist + edge.weight; if (distanceToNext < distances[nextCity]) { // 找到了更优解 distances[nextCity] = distanceToNext; maxRescues[nextCity] = Math.max(maxRescues[current.city], rescues[nextCity]); waysCounts[nextCity] = waysCounts[current.city]; // 更新路径 pq.offer(new State(nextCity, distanceToNext, maxRescues[nextCity])); } else if (distanceToNext == distances[nextCity]) { // 同样优秀的解 if (maxRescues[nextCity] < maxRescues[current.city] + rescues[nextCity]) { maxRescues[nextCity] = maxRescues[current.city] + rescues[nextCity]; } waysCounts[nextCity] += waysCounts[current.city]; } } } return new Result(maxRescues[endCity], waysCounts[endCity]); } static class Edge { int to; int weight; public Edge(int to, int weight) { this.to = to; this.weight = weight; } } static class Result { int maxRescue; int waysCount; public Result(int maxRescue, int waysCount) { this.maxRescue = maxRescue; this.waysCount = waysCount; } } } ``` 此程序读取标准输入的据构建图模型,并调用优化后的 Dijkstra 算法计算从起点至终点的佳路线及对应的救援量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值