算法描述
dijkstra算法的步骤如下:
- 初始化
dist[1]=0
,其余节点为无穷大 - 找到一个不在最短集合内的最小节点
x
,将其加入最短集合队列 - 扫描节点
x
的所有出边(x,y,z)
,若dist[y]>dist[x]+z
,则使用dist[y]=z
来更新dist[y]
- 重复上述2~3步骤,直到所有节点都被标记
第一种写法(邻接矩阵存储)
const int N=510,INF=1e9;
int g[N][N]; // g[i][j] 存的是第i点到第j点的距离
int dis[N]; // dis[i] 存的是第一个点到第i点的距离
int n,m; // n为顶点数,m为边数
bool st[N]; // st[]存已经是最短路径的点
void dijkstra(){
memset(dis,0x3f,sizeof dis); // dis 初始化为0x3f3f3f3f (任意一个取不到的值即可)
dis[1]=0;
for(int i=1;i<=n;i++){ // 遍历n次
int t=0; // 找到当前st[]=false 的最小值的顶点
for(int j=1;j<=n;j++){
if(!st[j]&& dis[j]<dis[t])
t=j;
}
st[t]=1; // 将当前顶点加入st[]
for(int j=1;j<=n;j++){ // 更新dis
dis[j]=min(dis[j],dis[t]+g[t][j]); //
}
}
// dis[i] 存的是第一个点到第i个点的距离
// 若为0x3f3f3f3f,则不存在路径
}
算法评价
该算法的时间复杂度为O(n^2)
,适合存储稠密图,主要用于寻找最小边,每次复杂度为O(n)
,n
次就为O(N^2)
,这里我们可以使用小根堆在O(logn)
获取最小值,并从堆中删除,最后在O(mlogn)
时间内来实现Dijkstra算法
第二种写法(邻接表存储)
const int N=1.5e5+10;
typedef pair<int,int>PII;
int h[N],e[N],ne[N],w[N],idx;
int n,m;
int dis[N];
bool st[N];
void add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void dijkstra(){
memset(dis,0x3f,sizeof dis);
dis[1]=0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,1});
while(heap.size()){
PII t=heap.top();
heap.pop();
int distance=t.first,ver=t.second;
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});
}
}
}
}
算法评价
该算法的时间复杂度为O(mlogn)
,适合存储稀疏图,这里的小根堆可用priority_queue
来实现,默认为大根堆,若想改成小根堆,第一种是代码中的写法,第二种是插入相反数就成了小根堆