Dijkstra算法
Dijkstra算法也是解决单源最短路问题的算法,他的算法利用了贪心的思想,不能有负边权。
算法步骤
- 首先将与起点s相连的结点全部放入集合中,找出距离最小的一个结点u,那么u就是第一个确定最短路径的结点。从s到u的路径肯定是最短的,因为s绕道别的地方在到u必然更远。
- 然后将继续取出集合中距离s最短的结点u,再将与u相连的结点放入集合。
- 继续以上的操作,在每一次迭代过程中都能确定一个结点的最短路径。
算法分析
-
图存储问题:使用链式前向星存储,防止图过大空间不够。
-
如何在每次迭代时快速找到集合中距离最小的结点:利用小根堆的数据结构来处理,每次的堆顶元素就是集合中最小的结点,这里我使用C++的STL中的priority_queue<>优先队列,切记如果找到最小结点必须要标记当前结点已是最短距离,后面不需要再访问。
-
时间复杂度:O(mlog2(n))
代码
typedef pair<int,int> PII;//相当于一个结构体:first表示最短距离,second表示结点编号
int d[N];
int e[N],ne[N],w[N],idx;//e[i]位置i的边所指向的结点 ne[i]位置i所指向的下一个位置 w[i]位置i的边的权值
int h[N];//h[u]表示与结点u连接的第一条边的位置
int b;//起点
bool vis[N];//表示结点i的最短路是否已找到。
void init()
{
memset(d,0x3f,sizeof d);//初始化初始距离为无限大
memset(h,-1,sizeof h);//初始化h所指向的位置为-1
}
void add(int a,int b,int c)//往图中添加边和结点
{
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void Dijkstra()
{
priority_queue<PII,vector<PII>,greater<PII> > heap;
heap.push({0,b});
d[b]=0;
while(!heap.empty())
{
auto t=heap.top();heap.pop();//取出集合中距离最小的结点,然后删除
int from=t.second,mind=t.first;
if(vis[from]) continue;//如果以使用过不在使用
vis[from]=1;//设置结点from已经使用过
for(int i=h[from];~i;i=ne[i])//遍历以from为起点的边
{
int to=e[i];
if(d[to]>d[from]+w[i])
{
d[to]=d[from]+w[i];
heap.push({d[to],to});
}
}
}
}