朴素dijkstra算法模板:(针对稠密图)
注释:st数组为判断是否搜索过的数组,g[n][m]数组为邻阶矩阵,n和m分别指两条边(n指向m),g[n][m]对应的值就是n到m边的权重,数组dist[N]为存每个点到源点的最短距离。
上思路:
-
初始化所有点到源点的最短距离为正无穷(当然真正在实现时不会定义为无穷);
-
开始for循环n次,每次枚举一个点,循环结束,即可枚举完所有点,求到每个点到源点的最短距离。
-
在上一步的for循环里,再嵌套一层循环,从i=1开始循环,<=n,目的为寻找当前未被搜索过点里,里源点最近的点,且定义为t;
-
最后再用t点去更新其他点到源点的最短距离
上代码:
#include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N=520,M=520; int g[N][M],n,m; bool st[N]; int dist[N]; int dijkstra() { memset(dist,0x3f,sizeof dist);//初始化最短距离数组 dist[1]=0;//定义第一个点的最短距离为0 for(int i=0;i<n;i++)//遍历每个点 { int t=-1;//定义为被搜索且离零点最近的点 for(int j=1;j<=n;j++)//搜索目前离源点最近的点 { if(!st[j]&&(t==-1||dist[t]>dist[j])) t=j;//j为目前离源点最近的点,并将t定义为j } st[t]=true;//标记已经搜索过 for(int j=1;j<=n;j++)//利用t点去更新后面点到源点的最短距离 dist[j]=min(dist[t]+g[t][j],dist[j]); } if(dist[n]==0x3f3f3f3f)return -1; else return dist[n]; } int main() { memset(g,0x3f,sizeof g); cin>>n>>m; while(m--) { int a,b,c; cin>>a>>b>>c; g[a][b]=min(c,g[a][b]); } cout<<dijkstra(); return 0; }
堆优化dijkstra求最短路(针对稀疏图):
思路:1.在原朴素版dijkstra基础上,主要变化是用堆(优先队列)来存储并遍历每一个点,而且要用邻接表来存图,因为这是稀疏图,此次要主要c++的优先队列(堆)默认是大根堆,这里需要定义为小根堆,操作为:priority_queue<PII,vector<PII>,greater<PII>>,且模板类似bfs框架。
2.第一步初始化距离dist数组为无穷大。
3.将源点入队,即head.push({0,1})0代表离源点最近的距离,1代表点的编号。
4.接下来就是bfs模板(判断队列是否为空,然后取出对头元素,再删除队头元素。
5.这里注意需要处理冗(rong)余备份,即我们还要一个用来判断这个点是否遍历过的一维数组st,如果st[i]=true,表示此点搜索过,为冗余备份,直接continue。
6.接下来就是和朴素dijkstra一模一样的利用当前点去更新所有点到源点最短距离的步骤,不过这里多了一步,就是如果有一个点被处理过了就将这个点入队。
7.还有就是用邻接表存的时候还有有一个专门存边的权重的数组,这里与普通邻接表有所不同,不过也好理解。
接下来上代码:
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int N=150010;
int h[N],e[N],ne[N],idx;
int n,m,dist[N];
bool st[N];int w[N];
void add(int x,int y,int z)
{
e[idx]=y,ne[idx]=h[x],w[idx]=z,h[x]=idx++;
}
int dijkstra(){
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>> head; memset(dist ,0x3f,sizeof dist);//初始化距离数组 dist[1]=0; head.push({0,1});//先将源点入队 while(head.size()) { auto t=head.top(); head.pop(); int ver=t.second,distance=t.first; if(st[ver])continue;//处理冗余备份 st[ver]=true; for(int i=h[ver];i!=-1;i=ne[i])//用当前点来更新后面所有点 { int j=e[i]; if(dist[j]>dist[ver]+w[i]) { dist[j]=dist[ver]+w[i]; head.push({dist[j],j}); } } } if(dist[n]==0x3f3f3f3f)return -1; else return dist[n];
}
int main(){
cin>>n>>m; memset(h,-1,sizeof h); while(m--) { int a,b,c; cin>>a>>b>>c; add(a,b,c); } cout<<dijkstra(); return 0;
}