PAT甲级1003Emergency
题目链接
https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
题解
题目要求
-
有几个城市,每个城市中有多个救援队,城市间由公路相连,公路的长度不一
-
输入
-
N:正整数,不超过500,城市的数量,城市索引为[0,N-1]
-
M:公路的数量
-
c1:你现在所在的城市
-
c2:你需要去的城市
-
各城市中救援队数量:N个整数
-
各条公路连接的两个城市其该公路的长度:M行
保证c1到c2至少有一条路径
-
-
输出
- c1到c2的最短路径的数量
- 在保证路径最短的前提下,最多可以聚集多少只救援队
解题思路
-
dijkstra算法
-
特点
- 适用于边权为正的情况
- 单源最短路(Single-Source Shortest Paths,SSSP),求单个源点到所有结点的最短路
- 同时适用于有向图和无向图
-
伪代码
n个结点
bool visited[n]; // 标记:是否找到源点s到某点的最短路径 int dis[n]; // 记录源点s到某点的最短路径的长度 int w[n][n]; // 结点间的距离 visited数组置false; dis数组置无穷大,dis[s]置0; 循环n次{ 寻找未被标记的、距离结点s最近的结点u; 如果找到u则将其标记(visited[u] = true),否则结束循环; 如果存在边<u,v>,则更新dis[v] = min(dis[v], dis[u] + w[u][v]); // 贪心 }
-
-
其它
-
c1到c2的最短路径的数量
pathNum
-
如果
dis[v] < dis[u] + w[u][v]
,则pathNum[v] = path[u]
u到v只有一条边,所以源点到u和v的路径的数量相等
-
如果
dis[v] == dis[u] + w[u][v]
,则pathNum[v] = path[u] + path[v]
在距离相等的情况下,除了经过u,还可以从其他结点到达v
-
-
在保证路径最短的前提下,最多可以聚集多少只救援队
-
如果
dis[v] < dis[u] + w[u][v]
,则teamGatherNum[v] = teamGatherNum[u] + teamNum[v]
-
如果
dis[v] == dis[u] + w[u][v]
,则teamGatherNum[v] = min(teamGatherNum[v], teamGatherNum[u] + teamNum[v])
此时最短路径不止一条,所以要判断哪条路径聚集的救援队更多
-
-
代码
// Problem: PAT Advanced 1003
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805523835109376
// Tags: 最短路 djikstra DFS 单源最短路 贪心
#include <iostream>
#include <climits>
using namespace std;
const int MAXN = 500; // 最多500个城市
const int INF = INT_MAX; // 最大距离
int cityDis[MAXN][MAXN]; // 城市间的距离
int teamNum[MAXN]; // 每个城市中有多少个救援队
int shortestPathDis[MAXN]; // 起点城市c1到各个城市最短路径的距离
int shortestPathNum[MAXN]; // 起点城市c1到各个城市最短路径的数量
int teamGatherNum[MAXN]; // 从起点城市c1到各个城市的最短路径上,最多能聚集到多少个救援队
bool visited[MAXN]; // 标记:是否已求出起点城市c1到某城市的最短路径
int main()
{
// 初始化变量
fill(cityDis[0], cityDis[0] + MAXN * MAXN, INF);
fill(shortestPathDis, shortestPathDis + MAXN, INF);
// 读取输入
int n, m, c1, c2;
scanf("%d %d %d %d", &n, &m, &c1, &c2);
for (int i = 0; i < n; i++)
scanf("%d", &teamNum[i]);
int a, b, d;
for (int i = 0; i < m; i++){
scanf("%d %d %d", &a, &b, &d);
cityDis[a][b] = cityDis[b][a] = d;
}
// 初始化起点城市c1
shortestPathDis[c1] = 0;
teamGatherNum[c1] = teamNum[c1];
shortestPathNum[c1] = 1;
// 迭代直至求出起点城市c1到所有城市的最短距离
for (int i = 0; i < n; i++){
// 寻找未被标记的、距离起点城市c1最近的城市u(贪心)
int u = -1, minDis = INF;
for(int j = 0; j < n; j++){
if (!visited[j] && shortestPathDis[j] < minDis){
u = j;
minDis = shortestPathDis[j];
}
}
// 各城市都已被标记,则已求出结果,退出循环即可;否则根据贪心策略,现在已求出起点城市c1到城市u的最短距离
if (u == -1)
break;
visited[u] = true;
// 如果有边<u,v>,则更新城市v的相关变量(最简洁的dijkstra算法只更新shortestPathDis[v]即可)
for (int v = 0; v < n; v++){
if (!visited[v] && cityDis[u][v] != INF){
if (shortestPathDis[v] > shortestPathDis[u] + cityDis[u][v]){
shortestPathDis[v] = shortestPathDis[u] + cityDis[u][v];
shortestPathNum[v] = shortestPathNum[u];
teamGatherNum[v] = teamGatherNum[u] + teamNum[v];
}
else if (shortestPathDis[v] == shortestPathDis[u] + cityDis[u][v]){
shortestPathNum[v] = shortestPathNum[u] + shortestPathNum[v];
if (teamGatherNum[v] < teamGatherNum[u] + teamNum[v])
teamGatherNum[v] = teamGatherNum[u] + teamNum[v];
}
}
}
}
printf("%d %d", shortestPathNum[c2], teamGatherNum[c2]);
return 0;
}
参考链接
https://blog.csdn.net/liuchuo/article/details/52300668
https://blog.csdn.net/qq_35644234/article/details/60870719
作者:@臭咸鱼
转载请注明出处:https://www.cnblogs.com/chouxianyu/
欢迎讨论和交流!