单源最短路径(Single Source Shortest Path)--《算法导论》
来源:互联网 发布:sql复制数据库 编辑:程序博客网 时间:2024/05/16 04:34
关于最短路径的描述请参考维基百科Shortest Path
简单总结一下算法导论上描述的计算从单一节点源到图中每一节点的最短路径算法,Bellman-Ford算法及其优化版本spfa,以及对权重非负的图的Dijkstra算法。
基本操作
初始化节点源
设节点
INITIALIZE_SINGLE_SOURCE(G,
s )
for each veterxv∈G.V
v.d = INF
v.p = NIL
s.d = 0
松弛
RELAX(u,v)
if v.d>u.d+w(u,v)
v.d=u.d+w(u,v)
v.p=u
在介绍最短路径算法之前先简单介绍一些最短路的性质,但这里不做严格证明,证明详见算法导论。
最短路径的性质
三角不等式:
环路:
最短路径首先是不允许有负环的,因为如果有负环,那在负环路径上的节点可以绕着负环无穷多圈从而
子路径性质:最短路的子路径也是最短路,即如果路径
收敛性质:给定一个带权重的有向图,
路径松弛性质:设
这些性质是后续介绍的算法的基础,特别是其中的松弛操作。
Bellman-Ford
伪代码:
Bellman-Ford(G,s)
INITIALIZE_SINGLE_SOURCE(G,
s )
for i=1 to V-1
for each edge∈G.E
RELAX(u,v)
for each edge (u,v)∈G.E
ifv.d>u.d+w(u,v)
return FALSE
return TRUE
时间复杂度
但是该算法时间复杂度太大,通常我们使用它的优化版本。可以看到Bellman-ford算法,对每条边都松弛
SPFA(Shortest Path Faster Algorithm)
伪代码
spfa(G,s)
INITIALIZE_SINGLE_SOURCE(G,
s )Q.inqueue(s)
inq[s] = TRUE
whle !Q.empty()
vertex u = Q.pop()
for each edge(u,v)∈ AdjEdge[u]
if RELAX(u,v)∧ inq[v] ==FALSE
Q.inque(v)
if ++v.cnt>|V|
return FALSE
return TRUE
c++代码
bool spfa(int s){ // memset(cnt,0,sizeof(cnt[0])*nv);//记录数组,用于检测负环真正使用时若题目中告诉没有负环可不用 memset(d,INF,sizeof(d[0])*nv); memset(inq,false,sizeof(inq[0])*nv); d[s] = 0; memset(p,-1,sizeof(p[0])*nv); queue<int> q; q.push(s); inq[s] = true; while(!q.empty()) { int u = q.front();q.pop(); inq[u] = false; for(int i=first[u] ; i!=-1; i = nt[i])//用边集数组储存 { Edge &e = edges[i] ; //松弛 if(d[e.to]>d[u]+e.w) { d[e.to] = d[u]+e.w; p[e.to] = u; if(!inq[e.to]) { q.push(e.to); inq[e.to] = true; //if(++cnt[e.to]>nv)return false; } } } } return true;}
可以“感受”到该算法的复杂度会低于Bellman的算法,实际证明出来是
Dijkstra
这个算用于计算权重为正数的SP的时候会优于SPFA,用一般的二叉堆储存只需
算法描述
用一个优先队列储存所有节点,每次取出
伪代码
INITIALIZE_SINGLE_SOURCE(G,
s )Q(v)
while !Q.empty()vertex
u = Q.pop()
for each edge(u,v)∈ AdjEdge[u]
RELAX(u,v)
c++代码
void Dijkstra(int s){ memset(d,INF,sizeof(d[0])*nv); d[s] = 0; memset(p,-1,sizeof(p[0])*nv); memset(vis,fasle,sizeof(vis)) priority_queue<pii,vector<pii>,greater<pii> > q;//pair默认先比较第一个分量,{d,s} q.push(pii(0,s)); vis[s] = true; while(!q.empty()) { int u = q.top().second;q.pop(); if(vis[u])continue; vis[u] = true; for(int i = first[u] ; i!=-1 ; i = n[i]) { Edge &e = edges[i]; if(d[e.to]>d[u]+e.w) { d[e.to] = d[u]+e.w; //p[e.to] = G[u][i]//保存边 p[e.to] = u;//最短路径树中的父节点 q.push(pii(d[e.to],e.to)); } } }}
因为STL里面的priority_queue,不支持对
总结
对于一般的有负权重的最短路问题最好使用spfa,而只有正权重的图,使用Dijkstra往往更快。而对于一般的有向无环图直接使用BFS加上松弛已经足够。
附上一个代码测试题
HDU 2544 最短路
- 单源最短路径(Single Source Shortest Path)--《算法导论》
- AOJ GRL_1_A: Single Source Shortest Path (Dijktra算法求单源最短路径,邻接表)
- Single source shortest path
- 算法导论problem 24-5 Gabow's algorithm for single source shortest path
- 最短路径 Part I- Single source shortest path
- 两点之间最短路径算法(Single-Dijkstra-shortest path)
- Graph: Single Source Shortest Path(TODO)
- 算法导论 单源最短路径 DAG-SHORTEST-PATHS
- Single-source shortest path problem: SPFA vs. Dijkstra
- 最短路径算法(Shortest-path Algorithms)
- 所有节点对之间的最短路问题(All Pair Shortest Path)--《算法导论》
- 最短路径(Shortest Path)
- SPFA算法(Shortest Path Faster Algorithm)最短路径快速算法,队列优化
- 2011-02-27 CLRS Chapter24 Single-Source Shortest Paths 单源点最短路径
- 2011-02-28 CLRS Chapter24 Single-Source Shortest Paths (下) 单源点最短路径 下
- 最短路径问题:SPFA(Shortest Path Faster Algorithm)算法
- 最短路径图算法(shortest path dijkstra)
- 最短路径(SPF - Shortest Path Firsh) - Dijkstra算法
- c++将数据保存到txt
- Java抽象类的概念和使用
- POJ 1062 Dijkstra
- 计算器代码(Java)
- 讯飞语音合成_3_java web实现
- 单源最短路径(Single Source Shortest Path)--《算法导论》
- inode理解
- HTML网页编程(3)
- linux shell 基础整理
- linux文件交集差集
- BZOJ 2251 [2010Beijing Wc]外星联络
- maven+springMVC+hibernate项目搭建(一基础环境配置)
- Static 以及内存分配 /java初学
- Java中Math类中支持的方法