Dijkstra学习笔记
介绍
这个算法适用于非负权图中求单源最短路(一个顶点到其他所有顶点的最短路),有着稳定优秀的时间复杂度,暴力Dij时间复杂度为O(n2),堆优后为O(mlogn)。事实上m和n2是同阶的,不过一般情况下m远小于n2,这种图被称为稀疏图;而m相对较大的图则被称为稠密图,这种情况下暴力Dij可能要比堆优Dij更优。
该算法主要思想是将所有结点分为两个集合:已确定最短路径长度d[x]的与没确定的。最开始前面的集合中只有起点s。然后将前一个集合中的所有出边进行松弛,在后面的集合中选出最短路d[x]最小的结点并标记访问,加入前面的集合中。直到所有节点都访问过即后一个集合没有元素,算法结束。
可以通过反向建图(将每条有向边的起点与终点互换)来求所有点到达一个固定点的最短路,只需要反向建图之后以到达的点为起点进行Dij。
实现
存图
这里使用邻接表进行存图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const int MAXN = 100000 + 5; const int MAXM = 200000 + 5;
struct Edge { int e, next, d; }ed[MAXM];
int first[MAXN], en;
void add_edge(int s, int e, int d) { en++; ed[en].next = first[s]; first[s] = en; ed[en].e = e; ed[en].d = d; }
|
Dijkstra
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| int d[MAXN]; bool vis[MAXN]; priority_queue< pair<int, int>, vector< pair<int, int> >, greater< pair<int, int> > > q;
inline void Dijkstra(int s) { memset(d,0x3f,sizeof(d)); d[s] = 0; q.push(mark_pair(0, s)); while(!q.empty()) { int now = q.top().second; q.pop(); if(!vis[now]) { vis[now] = true; for(int i = first[now]; i; i = ed[i].next) { int e = ed[i].e; if(d[e] > d[now] + ed[i].d) { d[e] = d[now] + ed[i].d; q.push(make_pair(d[e], e); } } } } }
|
相关文章
SPFA学习笔记 | Ender’s blog
Floyd学习笔记 | Ender’s blog