PAT(Advanced)1003 Emergency (Dijkstra最短路) (邻接矩阵)C++实现
PAT(Advanced)甲级1003 Emergency (Dijkstra最短路) (邻接矩阵)C++实现
题目链接
PAT(Advanced)1003
题目大意
在给定的图中,求解从起始顶点到目标顶点之间最短路径,输出不同最短路径的最大数目(路径不同,距离相同且最短),图中的每个顶点中都有救援队的数目,输出在所有最短路径中可以经过的含有最多的救援队的数量。
AC代码
#include<bits/stdc++.h>
using namespace std;const int INF = 0xFFFFF;
const int MAX_SIZE = 500;
int matrix[MAX_SIZE][MAX_SIZE];// 邻接矩阵数组
int teamNum[MAX_SIZE];// 存储输入数据各个城市的队伍数量
bool tag[MAX_SIZE];// 用于标记该顶点是否已经访问过
int DijkstraSSSP[MAX_SIZE];// 用于存储更新该点上一个相邻最短路上的顶点,递归回溯可以得到最短路径
int dist[MAX_SIZE];// 用于维护起始点到每个一个点的最短距离
int teamAnswer[MAX_SIZE];// 用于维护各个顶点在最短路上可呼叫的最大救援队数目
int pathNum[MAX_SIZE];// 用于维护从起始顶点到达各个顶点的最短路径最大数目
int N, M, start, target;// 顶点数、边数、起始顶点、目标顶点struct Node{int num;int dist;bool operator < (const Node& rhs) const{//最小堆return dist > rhs.dist;}
};// 记录顶点索引和该顶点与起始顶点的当前最短距离, 作为最小堆的节点void CreateNet(vector< pair< pair<int,int>, int> > net){// 输入数据输入邻接矩阵中存储for(int i = 0; i < N; i++){for(int j = 0; j < N; j++)matrix[i][j] = INF;}for(int i = 0; i < net.size(); i++){matrix[net[i].first.first][net[i].first.second] = net[i].second;matrix[net[i].first.second][net[i].first.first] = net[i].second;}
}void Dijkstra(int node){// 初始化,dist数组置为无穷大for(int i = 0; i < N; i++) {dist[i] = INF;teamAnswer[i] = teamNum[i];pathNum[i] = 0;DijkstraSSSP[i] = 0;tag[i] = false;}priority_queue<Node> Q;// 用优先队列实现的最小堆, 方便得到最小距离顶点Q.push((Node){node, 0});// 将第一个放入堆中dist[node] = 0;//自身距离置为0teamAnswer[node] = teamNum[node];DijkstraSSSP[node] = node;//最短路径while(!Q.empty()){int top = Q.top().num;// 从最小堆中取得与起始点距离最小的点Q.pop();if(tag[top]) continue;// 若已经存入已遍历集合, 则跳过tag[top] = true;pathNum[node] = 1;// 起始顶点的最短路径数为1for(int i = 0; i < N; i++){// 更新最短距离if(dist[i] >= dist[top] + matrix[top][i]) {// 递归地,更新最短路径数, 取决于顶点i上一个顶点top的最短路径数目// 若出现更小的, 更新为顶点top的最短路径数, 相同则加上if(dist[i] > dist[top] + matrix[top][i]) pathNum[i] = pathNum[top];else pathNum[i] += pathNum[top];dist[i] = dist[top] + matrix[top][i];DijkstraSSSP[i] = top;Q.push((Node){i, dist[i]});// 维护最短路经过的可呼叫的队伍的数目if(teamAnswer[i] < teamAnswer[top] + teamNum[i]) {teamAnswer[i] = teamAnswer[top] + teamNum[i];}}}}
}int main(int argc, char const *argv[])
{vector< pair< pair<int,int>, int> > net;int node1, node2;int weight;while(~scanf("%d%d%d%d", &N, &M, &start, &target)) {for(int i = 0; i < N; i++) {scanf("%d", &teamNum[i]);}for(int i = 0; i < M; i++) {scanf("%d%d%d", &node1, &node2, &weight);net.push_back(make_pair(make_pair(node1, node2), weight));}CreateNet(net);Dijkstra(start);printf("%d %d\n", pathNum[target], teamAnswer[target]);}return 0;
}
算法思路
基于Dijkstra单源最短路算法,采用邻接矩阵存放无向图,在算法中不断更新dist数组的过程中,同时更新起始点到各个顶点的最短路径最大数量和可呼叫救援队伍的最大数量。Dijkstra算法采用优先队列(最小堆)维护已遍历集合,便于得出每次集合的中与起始顶点距离最小的顶点。
样例测试
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
样例输出
2 4
样例图解
蓝色为该城市救援队数量, 绿色为边的权值
鸣谢
感谢PAT提供的题目及测评平台
上述的Dijkstra算法借鉴了刘汝佳和陈锋编著的算法竞赛入门经典:训练指南的Dijkstra算法
最后
需要注意的是,在求得最短路径数目的时候,每个顶点的最短路径数目取决于与在最短路径它连接的上一个顶点的路径数目,需要递归地进行,继承上一个顶点的最短路径数目(出现更短的路则直接继承,否则加上),才能得到正确的答案,博主刚开始忽略这个问题,只是使对应变量自增而导致了WA!
由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
PAT(Advanced)1003 Emergency (Dijkstra最短路) (邻接矩阵)C++实现
PAT(Advanced)甲级1003 Emergency (Dijkstra最短路) (邻接矩阵)C++实现
题目链接
PAT(Advanced)1003
题目大意
在给定的图中,求解从起始顶点到目标顶点之间最短路径,输出不同最短路径的最大数目(路径不同,距离相同且最短),图中的每个顶点中都有救援队的数目,输出在所有最短路径中可以经过的含有最多的救援队的数量。
AC代码
#include<bits/stdc++.h>
using namespace std;const int INF = 0xFFFFF;
const int MAX_SIZE = 500;
int matrix[MAX_SIZE][MAX_SIZE];// 邻接矩阵数组
int teamNum[MAX_SIZE];// 存储输入数据各个城市的队伍数量
bool tag[MAX_SIZE];// 用于标记该顶点是否已经访问过
int DijkstraSSSP[MAX_SIZE];// 用于存储更新该点上一个相邻最短路上的顶点,递归回溯可以得到最短路径
int dist[MAX_SIZE];// 用于维护起始点到每个一个点的最短距离
int teamAnswer[MAX_SIZE];// 用于维护各个顶点在最短路上可呼叫的最大救援队数目
int pathNum[MAX_SIZE];// 用于维护从起始顶点到达各个顶点的最短路径最大数目
int N, M, start, target;// 顶点数、边数、起始顶点、目标顶点struct Node{int num;int dist;bool operator < (const Node& rhs) const{//最小堆return dist > rhs.dist;}
};// 记录顶点索引和该顶点与起始顶点的当前最短距离, 作为最小堆的节点void CreateNet(vector< pair< pair<int,int>, int> > net){// 输入数据输入邻接矩阵中存储for(int i = 0; i < N; i++){for(int j = 0; j < N; j++)matrix[i][j] = INF;}for(int i = 0; i < net.size(); i++){matrix[net[i].first.first][net[i].first.second] = net[i].second;matrix[net[i].first.second][net[i].first.first] = net[i].second;}
}void Dijkstra(int node){// 初始化,dist数组置为无穷大for(int i = 0; i < N; i++) {dist[i] = INF;teamAnswer[i] = teamNum[i];pathNum[i] = 0;DijkstraSSSP[i] = 0;tag[i] = false;}priority_queue<Node> Q;// 用优先队列实现的最小堆, 方便得到最小距离顶点Q.push((Node){node, 0});// 将第一个放入堆中dist[node] = 0;//自身距离置为0teamAnswer[node] = teamNum[node];DijkstraSSSP[node] = node;//最短路径while(!Q.empty()){int top = Q.top().num;// 从最小堆中取得与起始点距离最小的点Q.pop();if(tag[top]) continue;// 若已经存入已遍历集合, 则跳过tag[top] = true;pathNum[node] = 1;// 起始顶点的最短路径数为1for(int i = 0; i < N; i++){// 更新最短距离if(dist[i] >= dist[top] + matrix[top][i]) {// 递归地,更新最短路径数, 取决于顶点i上一个顶点top的最短路径数目// 若出现更小的, 更新为顶点top的最短路径数, 相同则加上if(dist[i] > dist[top] + matrix[top][i]) pathNum[i] = pathNum[top];else pathNum[i] += pathNum[top];dist[i] = dist[top] + matrix[top][i];DijkstraSSSP[i] = top;Q.push((Node){i, dist[i]});// 维护最短路经过的可呼叫的队伍的数目if(teamAnswer[i] < teamAnswer[top] + teamNum[i]) {teamAnswer[i] = teamAnswer[top] + teamNum[i];}}}}
}int main(int argc, char const *argv[])
{vector< pair< pair<int,int>, int> > net;int node1, node2;int weight;while(~scanf("%d%d%d%d", &N, &M, &start, &target)) {for(int i = 0; i < N; i++) {scanf("%d", &teamNum[i]);}for(int i = 0; i < M; i++) {scanf("%d%d%d", &node1, &node2, &weight);net.push_back(make_pair(make_pair(node1, node2), weight));}CreateNet(net);Dijkstra(start);printf("%d %d\n", pathNum[target], teamAnswer[target]);}return 0;
}
算法思路
基于Dijkstra单源最短路算法,采用邻接矩阵存放无向图,在算法中不断更新dist数组的过程中,同时更新起始点到各个顶点的最短路径最大数量和可呼叫救援队伍的最大数量。Dijkstra算法采用优先队列(最小堆)维护已遍历集合,便于得出每次集合的中与起始顶点距离最小的顶点。
样例测试
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
样例输出
2 4
样例图解
蓝色为该城市救援队数量, 绿色为边的权值
鸣谢
感谢PAT提供的题目及测评平台
上述的Dijkstra算法借鉴了刘汝佳和陈锋编著的算法竞赛入门经典:训练指南的Dijkstra算法
最后
需要注意的是,在求得最短路径数目的时候,每个顶点的最短路径数目取决于与在最短路径它连接的上一个顶点的路径数目,需要递归地进行,继承上一个顶点的最短路径数目(出现更短的路则直接继承,否则加上),才能得到正确的答案,博主刚开始忽略这个问题,只是使对应变量自增而导致了WA!
由于博主水平有限,不免有疏漏之处,欢迎读者随时批评指正,以免造成不必要的误解!
发布评论