对于单源最短路所有边都为正权边但是为稀疏图的最短路问题,应该采用堆优化版本的dijkstra算法,具体的优化是将朴素版的dijkstra算法中的寻找最短路径使用堆来优化,使本来在n次中遍历n次的n^2操作变为n*1,但是堆优化会导致后续的使用迭代的点更新距离的方法变为堆中需要logn才能修改一次,且一共修改m条边次,故时间复杂度使mlogn。
其中堆优化可以分为两种方式,一种是手写堆,这种的优势是正统的mlogn时间复杂度,但是写的过程会比较复杂,还有一种方式是借用c++中的优先队列(priority——queue)容器,可以更快的完成默写过程,但是由于优先队列是无法进行插入操作的所以需要mlogm的时间,时间更复杂一些。
同样也有两个方面需要关注一下。定义和算法的实现。
定义上,因为是稀疏图,所以一般采用邻接表的方式来存储数据(链表)。
int N 题目给的数据范围, bool st[N]判断是否已经知道最短路, int dis[N]存储到该点的距离, int h[N] 模拟头结点,链表通过头节点后一串链表来表示该头节点有多少条边,且各个边没有先后顺序, int w[N]用来记录该边有多长, int ne[N]链表中记录下一个点的地址, int e[N]记录下一个点的数值。
using namespace std;
typedef pair<int,int>PII;
const int N=1000010;
int w[N],ne[N],e[N],h[N],idx,n;
int dis[N];
bool st[N];
还有一个需要实现的优先队列priority_queue<PII,vector<PII>,greater<PII>>heap;(这是一个小根堆,自动维护从小到大的顺序)
算法的实现1.初始化,需要将头节点初始化-1,将1号点距离为0的队列插入优先队列中。
2.遍历寻找堆头元素的边可以达到的点,找到可以达到点的更小值,将值插入优先队列中。
给个具体的模板
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
const int N=1000010;
int w[N],ne[N],e[N],h[N],idx,n;
int dis[N];
bool st[N];
void add(int a,int b,int c){
e[idx]=b;
ne[idx]=h[a];
h[a]=idx;
w[idx]=c;
idx++;
}
int dijkstra()
{
memset(dis,0x3f,sizeof dis);
dis[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
auto t=heap.top();
heap.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(dis[j]>dis[ver]+w[i]){
dis[j]=dis[ver]+w[i];
heap.push({dis[j],j});
}
}
}
if(dis[n]==0x3f3f3f3f) return -1;
else return dis[n];
}
int main()
{
int m;
memset(h,-1,sizeof h);
cin >> n >> m;
for(int i=0;i<m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
}
cout << dijkstra();
return 0;
}
针对稀疏图的单源最短路径问题,介绍堆优化Dijkstra算法的具体实现,包括使用优先队列进行优化以降低时间复杂度,并提供了一个C++实现的代码模板。
1745

被折叠的 条评论
为什么被折叠?



