【模板算法】单源最短路问题-dijkstra算法(邻接表+优先队列优化)
2018-03-17 13:05
393 查看
dijkstra算法适用范围:
求一个点到另一个点或其他点的最短路问题,当然,最大路也可以,重载一下<号即可。我写的这次模板是双条件的,即除了路径长度限制还有当路径长度相同后data小的优先输出,并且还有返回路径的函数,所以普适度更高,如果做得题目不需要双条件,删除data相关内容即可。在该篇文章最后会有源代码及两组测试数据供大家测试。edge结构体定义
struct edge{ int length,data,to; edge(int a,int b,int c):length(a),data(b),to(c){} bool operator <(const edge &a)const{//使优先队列从小到大输出 return length == a.length ? data > a.data : length > a.length; } };
dijkstra算法具体实现
#define MAX_N 510 #define INF 99999999 int N,M,start,end,d[MAX_N][2];//总点数,总路径数,起点,终点,保存当前从起点出发最短路径(优先)及最小的data int pre[MAX_N],ans[MAX_N],ccount=0;//保存前驱节点,保存路径,用于计数路径长度 vector<edge> G[MAX_N]; //邻接表初始化 priority_queue<edge> q;//优先队列存的是d[s][0],d[s][1],s,s为当前搜索的节点; int dijkstra(int s){ for(int i=0;i<N;i++){// d[i][0]=d[i][1]=INF; pre[i]=-1; } d[s][0]=d[s][1]=0; q.push(edge(0,0,s));//将起点压入队列 while(!q.empty()){ edge p=q.top();q.pop(); int v=p.to; if(d[v][0]<p.length) continue;//如果d[v][0]不是最短距离,则跳过 for(int i=0;i<G[v].size();i++){//更新所有与v相连的点 edge e=G[v][i]; if(d[e.to][0]>d[v][0]+e.length||(d[e.to][0]==d[v][0]+e.length&&d[e.to][1]>d[v][1]+e.data)){ //如果搜索的点的最短距离>当前点的最短距离加上它们之间的路径,则更新 //如果搜索的点的最短距离=当前点的最短距离加上它们之间的路径,则判断data大小,如果大于,则更新 d[e.to][0]=d[v][0]+e.length; d[e.to][1]=d[v][1]+e.data; pre[e.to]=v;//此处保存的即为前驱节点 q.push(edge(d[e.to][0],d[e.to][1],e.to)); } } } }
通过前驱节点输出路径
不断向前搜索,知道前驱节点为-1为止,保存到ans数组中并输出void GetPath(){ int temp=end; while(temp!=-1){ ans[ccount++]=temp; temp=pre[temp]; } for(int i=ccount-1;i>=0;i--){ if(i==ccount-1) printf("%d",ans[i]); else printf("->%d",ans[i]); } }
完整代码
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<string> #include<vector> #include<queue> #include<algorithm> #define MAX_N 510 #define INF 99999999 using namespace std; int N,M,start,end,d[MAX_N][2]; int pre[MAX_N],ans[MAX_N],ccount=0; struct edge{ int length,data,to; edge(int a,int b,int c):length(a),data(b),to(c){} bool operator <(const edge &a)const{//使优先队列从小到大输出 return length == a.length ? data > a.data : length > a.length; } }; vector<edge> G[MAX_N]; priority_queue<edge> q;//优先队列存的是d[s][0],d[s][1],s,s为当前搜索的节点; int dijkstr 4000 a(int s){ for(int i=0;i<N;i++){ d[i][0]=d[i][1]=INF; pre[i]=-1; } d[s][0]=d[s][1]=0; q.push(edge(0,0,s)); while(!q.empty()){ edge p=q.top();q.pop(); int v=p.to; if(d[v][0]<p.length) continue; for(int i=0;i<G[v].size();i++){ edge e=G[v][i]; if(d[e.to][0]>d[v][0]+e.length||(d[e.to][0]==d[v][0]+e.length&&d[e.to][1]>d[v][1]+e.data)){ d[e.to][0]=d[v][0]+e.length; d[e.to][1]=d[v][1]+e.data; pre[e.to]=v; q.push(edge(d[e.to][0],d[e.to][1],e.to)); } } } } void GetPath(){ int temp=end; while(temp!=-1){ ans[ccount++]=temp; temp=pre[temp]; } for(int i=ccount-1;i>=0;i--){ if(i==ccount-1) printf("%d",ans[i]); else printf("->%d",ans[i]); } } int main(){ scanf("%d%d%d%d",&N,&M,&start,&end); int a,b,c,d; for(int i=0;i<M;i++){ scanf("%d%d%d%d",&a,&b,&c,&d); G[a].push_back(edge(c,d,b)); G[b].push_back(edge(c,d,a)); } dijkstra(start); GetPath(); exit(0); }
测试数据
Sample Input 17 9 3 5
0 4 1 1
1 6 1 3
2 6 1 1
2 5 2 2
3 0 1 1
3 1 1 3
3 2 1 2
4 5 2 2
6 5 1 2
Sample Input 2
10 15 3 5
0 1 1 1
8 0 1 1
4 8 1 1
3 4 3 2
3 9 4 1
0 6 1 1
7 5 2 1
8 5 2 1
2 3 2 2
2 1 1 1
1 3 3 1
1 4 1 1
9 7 3 1
5 1 5 2
6 5 1 2
相关文章推荐
- 总结分析一下三种求解最短路问题的算法,dijkstra算法,spfa算法,floyd算法。
- 单源最短路问题模板(Dijkstra+Bellman-Ford)
- 单源最短路问题模板
- 单源最短路问题 dijkstra算法 总结
- HDU 1874 畅通工程续(最短路问题 Dijkstra算法) O(V*E)
- 2018年全国多校算法寒假训练营练习比赛(第三场)E---进击吧!阶乘(Java代码,另附Java解决大数问题的模板)
- Dijkstra算法是解单源最短路径问题的一个贪心算法
- Dijkstra算法(单源最短路问题)
- 十二、图的算法入门--(4)最短路问题---Dijkstra算法实现
- 九度 OJ 1447 题 最短路径问题 Dijkstra(迪杰斯特拉)算法实现,使用vector模板模拟邻接链表
- HDOJ 1596 find the safest road(类最短路问题,dijkstra算法)
- 算法学习之Dijkstra单源最短路问题
- hdu 2544 单源最短路问题 dijkstra+堆优化模板
- 贪心算法之用优先队列解决最短路径问题(Dijkstra算法)
- 算法模板之最近公共祖先问题(LCA)
- 最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)
- Bellman-Ford 算法 & SPFA(单源最短路问题)
- 【解题报告】 POJ 1556 The Doors -- 最短路问题 Dijkstra算法 + 直线相交
- 矩阵模板 51nod 算法马拉松分解问题
- RMQ问题ST算法与模板(2007-07-15 15:48)