算法导论(MIT 6.006 第15讲 第16讲 第17讲)算法
最短路径即拥有最小权重的路径p;
路径定义: p=<,
,...,
>, 其中当
时,有 (
,
)
E;
路径的权重:w(p)= ;bash
E与V的关系 E=O(
)。对于有向图来说,假设有两个顶点,v1,v2,他们之间只有4种链接状况,依次类推网络
好比社交网络上的喜欢能够看作是正的权重,比喜欢能够看作是负的权重函数
若是存在一个带有负权重的边,那么每通过一个循环,会减小原有的权重值,这样形成的现象是能够获得任何能够获得的权重值。好比路径p=<S,A>权重是4,可是路径p=<S,A,C,B,A>权重是3spa
d(v) 表示从源点s到当前节点v的路径权重 ,
表示当前最好的路径上,v的前一个节点 ,经过这种方式就能重构整个最短路径.net
针对没有负权重的环3d
Relax(u,v,w):
select edge(u,v):
if d[v]>d[u]+w(u,v):
d[v]=d[u]+w(u,v)
PI[v]=u
until all edges have d[v] <= d[u]+w(u,v)
复制代码
经过概括法,假设有 d[u]
(s,u)。已知的是
表示s到v的最短路径,那么任意一个到v的顶点u和源点s到u的最短路径一定大于等于
,也就是code
经过前面的假设,则一定有 。这说明,中间的过程的任意一个阶段产生的结果d[v]都不会比
(s,v)还要小cdn
构造以下结构的图blog
边的权值按照
方式分配,图中给出的6个点的示例,若是所有显示的边(
,
)的权值为
,并依次递减到1
此时,Relax(,
)的边,会更新
到
的路径长度为13
可发现,当Relax的边(,
)权重为1的时候,使得顶点d(
)减1;当Relax边(
,
)权重为2的时候,使得顶点d(
)减2,也就是从权重按照 1,2,4,...,
,
的方式执行的过程当中,d(
)须要执行减小的总次数为1+2+4+...+
=
,也就是说,会执行的次数为指数级别
若是在源点到目标节点通过的路径上,通过环会致使权重减小,这个算法不会结束
DAG表示只是没有环,能够存在负边权重
假设排序好的拓扑图以下,对于初始化时,每一个源点到每一个节点的距离都认为是
继续往右执行Relax
至此执行完毕,能够看到源点到全部节点的最短路径,从左到右分别是 ,0,2,6,5,3
使用Dijkstra算法。伪代码算法以下:
Dijkstra(G,w,s): //G是图,w是权值,s是源点
Initialize(G,s) // 初始化,设置d[s]=0,其它都是无穷,以及PI
S <- {} //已知最短路径的点的集合
Q <- V[G] //须要被处理的顶点,能够看作是一个最小优先级队列,根据d()值进行排序
while Q is not empty: //只要还有没处理的节点
u <- Extract-Min(Q) //从节点中找出一个最小的路径权重的节点,并从Q中移除
S <- S U {u} //将找到的节点并到S中
for each vertex v belong to Adj
Relax(u,v,w) //对边的d()值进行更新
复制代码
例子以下,选择A为源点
括号中的值表示路径距离
全部的耗时操做包括:
最直观的使用Dijkstra的感觉是:如下图为例:
假设绿色的点是源点,若是用这样长度的绳子将各个节点链接起来,那么拎起绿色的球,从上往下悬挂,那些蹦直的线相加就是源点到各个点的最短距离,好比绿色是源点,到其它点的最短距离分别是 7,12,18,22(颜色依次是紫色、蓝色、黄色、红色) ![]()
Dikstra不会去看已经处理好的节点,只会处理没有看到的节点,若是已经处理的节点都是最小的值,再不存在负权重环的状况下,是不会出现使得路径变小的状况。详见:stackoverflow.com/questions/6…
使用Bellman-Ford算法。
Bellman-Ford(G,w,s):
Initialuze(G,s)
for i=1 to |V|-1:
for each edge(u,v) belong to E:
Relax(u,v,w)
for each edge (u,v) belong to E:
if d[v]>d[u]+w(u,v)
report negative cycle exist
复制代码
Bellman-Ford最终提供的是,若是没有负权重的环,那么能返回最短路径(d[v]=),不然只是检测出存在负权重的环
两个for循环,分别为V,E,因此时间复杂度就是O(VE)
只须要证实,若是不存在负权重的环,那么通过Bellman-Ford有d[v]=。
取一条拥有最少边的最短路径p=<,
,...,
>,其中
为s,
=v。 若是不存在负权重的环,那么说明p是一条简单路径,这代表,k
|V|-1。
这里也不多是一个正环,即每通过这个环,权重增长,若是是那么它就不是最短路径了
当进行第一次循环的时候,取到的边(,
)进行了Relax,那么有
进行第二次循环,取到的边(
,
)进行了Relax,那么有
那么通过k轮循环以后,有,也就是说通过了|V|-1轮循环以后,每一个从源点可达的顶点都计算了最短路径
简单路径(simple path):指除了起点和终点以外,其它顶点不会重复。对于简单路径p=<
,
,...,
>来说,若是k>=|V|,那么路径上总的顶点数是|V|+1,但实际只有 |V|个顶点,那么一定存在一条重复的边,使得非起点终点重复了,也就是说他不是简单路径了
通过|V|-1轮循环以后,若是还有一条边可以Relax,那么当前从s到v的最短路径并非简单路径,由于全部的节点都已经看过了,这时候确定存在了重复的节点,也就是说存在一个负权重的环
不能,由于Bellman-Ford对于存在负权重的环的时候只会抛出异常,并无计算路径,这实际是一个N-P的问题,即花的时间在指数级别或者之上
相似的,若是要求不通过负权重的环的状况下,计算最短路径,也并非件容易的事情