城市间紧急救援(Dijkstra算法)

       作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:
       输入第一行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0 ~ (N−1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。

       第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:
       第一行输出最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出结尾不能有多余空格。

输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3

       关于最短路径的求法并且是正权问题毫无疑问用dijkstra算法,采用if(dis[j] > dis[u] + ma[u][j]) dis[j] = dis[u][j] + ma[u][j],让我大致把代码梳理一下

	for(i = 0; i < n; ++i)
	{
		for(j = 0; j < n; ++j)
		{
			ma[i][j] = INF;
		}
		ma[i][i] = 0;
	}

       这里先对二维矩阵进行初始化,因为自己到自己的距离为0,所以ma[i][i] = 0;

	for(i = 0; i < m; ++i)
	{
		scanf("%d%d%d", &u, &v, &w);
		ma[u][v] = w;
		ma[v][u] = w;
	}

       这里就是将整幅地图都存在二维矩阵之中,路与路之间是双向连通,所以是一个无向图,ma[u][v] = w,ma[v][u] = w;

void Dijkstra()//核心 
{
	int i, j;
	memset(vis, 0, sizeof(vis));
	memset(dis, INF, sizeof(dis));
	pathnum[s] = 1;
	numdis[s] = num[s];
	path[s] = -1;
	dis[s] = 0;
	for(i = 1; i <=  n; ++i)
	{
		int mn = INF, u;
		for(j = 0; j < n; ++j)
		{
			if(!vis[j] && dis[j] < mn)
			{
				mn = dis[j];
				u = j;	
			}	
		} 
		vis[u] = 1; 
		for(j = 0; j < n; ++j)
		{
			if(!vis[j])
			{
				if(dis[j] > dis[u] + ma[u][j])
				{
					dis[j] = dis[u] + ma[u][j];
					path[j] = u;
					pathnum[j] = pathnum[u];
					numdis[j] = numdis[u] + num[j];	
				}
				else if(dis[j] == dis[u] + ma[u][j])
				{
					pathnum[j] += pathnum[u];
					if(numdis[j] < numdis[u] + num[j])
					{
						numdis[j] = numdis[u] + num[j];
						path[j] = u;
					}
				}	
			}		
		}	
	}	
}

       这里是核心,首先进行初始化,memset(vis, 0, sizeof(vis)); 这里用来标记走过的点与没走过的点,刚开始都没有走过,所以全置为0,同样,最短距离置为无穷大,内部的第一层for循环主要是用来标记最短路径,下一层for就是dijkstra算法的核心,比较找出相邻城市的最短距离,通过不断的更新dis[j]、path[j]、pathnum[j]、numdis[j]来达到目的,特别要注意的是在距离相等的条件下寻找救援队数量最多的路径,此时的path[j]也需更新
       完整代码

#include <iostream>
#include <cstring>
using namespace std;
/*
	本题作为学习 
*/
#define INF 1000000
const int N = 510;
int vis[N];
int ma[N][N];
int dis[N];
int num[N];
int numdis[N];
int path[N];
int pathnum[N];
int n, m, s, d;
int ans[N], top = 0;

void Dijkstra()//核心 
{
	int i, j;
	memset(vis, 0, sizeof(vis));
	memset(dis, INF, sizeof(dis));
	pathnum[s] = 1;
	numdis[s] = num[s];
	path[s] = -1;
	dis[s] = 0;
	for(i = 1; i <=  n; ++i)
	{
		int mn = INF, u;
		for(j = 0; j < n; ++j)
		{
			if(!vis[j] && dis[j] < mn)
			{
				mn = dis[j];
				u = j;	
			}	
		} 
		vis[u] = 1; 
		for(j = 0; j < n; ++j)
		{
			if(!vis[j])
			{
				if(dis[j] > dis[u] + ma[u][j])
				{
					dis[j] = dis[u] + ma[u][j];
					path[j] = u;
					pathnum[j] = pathnum[u];
					numdis[j] = numdis[u] + num[j];	
				}
				else if(dis[j] == dis[u] + ma[u][j])
				{
					pathnum[j] += pathnum[u];
					if(numdis[j] < numdis[u] + num[j])
					{
						numdis[j] = numdis[u] + num[j];
						path[j] = u;
					}
				}	
			}		
		}	
	}	
}

void getpath(int x)
{
	if(path[x] != -1)
	{
		ans[top++] = x;
		getpath(path[x]); 
	}
	else
	{
		ans[top++] = x;
		return ;
	}
}
 
int main()
{
	int u, v, w, i, j;
	scanf("%d%d%d%d", &n, &m, &s, &d);
	for(i = 0; i < n; ++i)
	{
		for(j = 0; j < n; ++j)
		{
			ma[i][j] = INF;
		}
		ma[i][i] = 0;
	}
	for(i = 0; i < n; ++i)
	{
		scanf("%d", &num[i]);	
	}
	for(i = 0; i < m; ++i)
	{
		scanf("%d%d%d", &u, &v, &w);
		ma[u][v] = w;
		ma[v][u] = w;
	}
	Dijkstra();//核心 
	getpath(d);
	printf("%d %d\n", pathnum[d], numdis[d]);
	for(i = top - 1; i > 0; --i)
	{
		printf("%d ", ans[i]);	
	}
	printf("%d\n", ans[0]);
	return 0;	
}
### 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、付费专栏及课程。

余额充值