定义
Dijkstra 算法
由荷兰计算机科学家 E. W. Dijkstra 于 1956 年发现,1959 年公开发表的一种用于求解非负权图上单源最短路径的算法。
过程
设起点为,结点集合为,边集为。
同时设数组为到点的距离,和分别为已经确定最短路径和未确定最短路径的点集。
- 初始化:,其余。令。
- 选点:遍历,求出其中最小的结点。
- 松弛:遍历的出边以及对应的结点,如果到的距离加上出边的距离是否小于到的距离,则更新。即
- 重复:将从移到中,若不为空,重复2和3。
实现
朴素实现
struct edge
{
int v, w;
};
int N;
int n, m;
vector<edge> p[N];
int d[N],
bool vis[N];
void dijkstra(int s)
{
// 初始化
std::fill(dist, dist + N, 1e9);
dis[s] = 0;
for(int i = 1; i <= n; i++)
{
// 选点
int u = -1;
for(int j = 1; j <= n; j++)
if(!vis[j] && (u == -1 || d[j] < d[u]))
u = j;
vis[u] = true;
// 松弛
for(auto &edge : p[u])
{
int v = edge.v;
int w = edge.w;
if(d[u] + w < d[v])
d[v] = d[u] + w;
}
}
}
优先队列实现
利用优先队列,可以将取点操作的复杂度从降为。
struct edge
{
int v, w;
};
struct node
{
int u, d;
bool operator>(const node& a) const
{
return d < a.d;
}
}
int N;
int n, m;
vector<edge> p[N];
int d[N],
bool vis[N];
priority_queue<node, vector<node>, greater<node>> pq;
void dijkstra(int s)
{
// 初始化
std::fill(dist, dist + N, 1e9);
dis[s] = 0;
pq.push({s, 0});
while(pq.empty())
{
// 选点
int u = pq.top().u;
pq.pop();
// 已经确定的点直接跳过
if(vis[u] == true)
continue;
vis[u] = true;
// 松弛
for(auto &edge : p[u])
{
int v = edge.v;
int w = edge.w;
if(d[u] + w < d[v])
{
d[v] = d[u] + w;
pq.push({v, d[v]});
}
}
}
}