您的位置:首页 > 其它

【模板算法】单源最短路问题-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 1

7 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息