bellman-ford算法与差分约束系统
算法导论(第三版)-复习-第六部分图论22-26[转]
![算法导论(第三版)-复习-第六部分图论22-26[转]](https://img.taocdn.com/s3/m/056830c148649b6648d7c1c708a1284ac85005ae.png)
算法导论(第三版)-复习-第六部分图论22-26[转]22习题22.1-5 有向图G(V, E)的平⽅图。
链表表⽰时,对每结点u的Adj[u]中所有v加⼊队列,后边出队边将Adj[v]加⼊Adj[u]中。
矩阵表⽰时,若w[i, j]、w[j, k]同时为1则将w[i, k]置1.习题22.1-6 O(V)的时间寻找通⽤汇点。
汇点的特征是邻接矩阵的第j列除[j, j]外所有元素为1. 可将每⾏调整[j ,j]后作为⼀个整数,所有整数与运算,为1的位是汇点。
习题22.1-7 有向⽆环图的关联矩阵B,BB’每个元素C[i, j]=∑B[i, k]*B’[k, j]=∑B[i, k]*B[j, k],即同时进i, j两结点与同时出i, j的结点总数-⼀进⼀出i, j两结点的结点总数。
习题22.2-7 类似BFS,d mod2为0则标为B(娃娃脸),d mod2为1则标为H(⾼跟鞋)。
但若有边连接相同类的结点,则⽆法划分。
wrestler(G){for each u in G{(u,v)=Adj[u];if(v.mark==u.mark){throw error;}if(v.d==NIL) {v.d=u.d+1; v.mark=v.d mod 2;}}}习题22.2-8 任意点之间的最短路径。
重复的Dijktra算法或Floyd-Warshall算法习题22.2-9 ⽆向图扩展为有向图。
问题变成要遍历所有边⼀次。
访问结点u时,将u的⼦结点v的其他边都可视为⼦集v,问题等价于u到v,访问v的集合,v到u。
u标为visiting⼊列,然后访问v,v标为visiting⼊列,然后访问v的后继结点,访问过的边标为visited,返回到visiting的点时,如果该点所有连接的边都标为visited只剩⼀条返回上级的边,则返回上级结点并将点标为visited,v出列,访问u的其他⼦结点,最终u出列。
全部结点出列后达到遍历所有边⼀次。
【转】彻底弄懂最短路径问题(图论)

【转】彻底弄懂最短路径问题(图论)P.S.根据个⼈需要,我删改了不少问题引⼊问题:从某顶点出发,沿图的边到达另⼀顶点所经过的路径中,各边上权值之和最⼩的⼀条路径——最短路径。
解决最短路的问题有以下算法,Dijkstra算法,Bellman-Ford算法,Floyd算法和SPFA算法,另外还有著名的启发式搜索算法A*,不过A*准备单独出⼀篇,其中Floyd算法可以求解任意两点间的最短路径的长度。
笔者认为任意⼀个最短路算法都是基于这样⼀个事实:从任意节点A到任意节点B的最短路径不外乎2种可能,1是直接从A到B,2是从A经过若⼲个节点到B。
⼀.Dijkstra算法该算法在《数据结构》课本⾥是以贪⼼的形式讲解的,不过在《运筹学》教材⾥被编排在动态规划章节,建议读者两篇都看看。
(1) 迪杰斯特拉(Dijkstra)算法按路径长度递增次序产⽣最短路径。
先把V分成两组:S:已求出最短路径的顶点的集合V-S=T:尚未确定最短路径的顶点集合将T中顶点按最短路径递增的次序加⼊到S中,依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的直接路径的权值或是从V0经S中顶点到Vk的路径权值之和(反证法可证)。
(2) 求最短路径步骤1. 初使时令 S={V0},T={其余顶点},T中顶点对应的距离值,若存在<V0,Vi>,为<V0,Vi>弧上的权值(和SPFA初始化⽅式不同),若不存在<V0,Vi>,为Inf。
2. 从T中选取⼀个其距离值为最⼩的顶点W(贪⼼体现在此处),加⼊S(注意不是直接从S集合中选取,理解这个对于理解vis数组的作⽤⾄关重要),对T中顶点的距离值进⾏修改:若加进W作中间顶点,从V0到Vi的距离值⽐不加W的路径要短,则修改此距离值(上⾯两个并列for循环,使⽤最⼩点更新)。
3. 重复上述步骤,直到S中包含所有顶点,即S=V为⽌(说明最外层是除起点外的遍历)。
差分约束系统详解

差分约束系统在一个差分约束系统(system of difference constraints)中,线性规划矩阵A的每一行包含一个1和一个-1,A的其他所有元素都为0。
因此,由Ax≤b给出的约束条件是m个差分约束集合,其中包含n个未知量,对应的线性规划矩阵A为m行n列。
每个约束条件为如下形式的简单线性不等式:xj-xi≤bk。
其中1≤i,j≤n,1≤k≤m。
例如,考虑这样一个问题,寻找一个5维向量x=(xi)以满足:这一问题等价于找出未知量xi,i=1,2,…,5,满足下列8个差分约束条件:x1-x2≤0x1-x5≤-1x2-x5≤1x3-x1≤5x4-x1≤4x4-x3≤-1x5-x3≤-3x5-x4≤-3该问题的一个解为x=(-5,-3,0,-1,-4),另一个解y=(0,2,5,4,1),这2个解是有联系的:y中的每个元素比x中相应的元素大5。
引理:设x=(x1,x2,…,xn)是差分约束系统Ax≤b的一个解,d为任意常数。
则x+d=(x1+d,x2+d,…,xn+d)也是该系统Ax≤b的一个解。
约束图在一个差分约束系统Ax≤b中,m X n的线性规划矩阵A可被看做是n顶点,m条边的图的关联矩阵。
对于i=1,2,…,n,图中的每一个顶点vi对应着n个未知量的一个xi。
图中的每个有向边对应着关于两个未知量的m个不等式中的一个。
给定一个差分约束系统Ax≤b,相应的约束图是一个带权有向图G=(V,E),其中V={v0,v1,…,vn},而且E={ (vi,vj) : xj-xi≤bk是一个约束}∪{ (v0,v1) , (v0,v2) , … , (v0,vn) }。
引入附加顶点v0是为了保证其他每个顶点均从v0可达。
因此,顶点集合V由对应于每个未知量xi的顶点vi和附加的顶点v0组成。
边的集合E由对应于每个差分约束条件的边与对应于每个未知量xi的边(v0,vi)构成。
如果xj-xi≤bk是一个差分约束,则边(vi,vj)的权w(vi,vj)=bk(注意i和j不能颠倒),从v0出发的每条边的权值均为0。
最短路算法(bellman-Ford算法)

最短路算法(bellman-Ford算法)贝尔曼-福特算法与迪科斯彻算法类似,都以松弛操作为基础,即估计的最短路径值渐渐地被更加准确的值替代,直⾄得到最优解。
在两个算法中,计算时每个边之间的估计距离值都⽐真实值⼤,并且被新找到路径的最⼩长度替代。
然⽽,迪科斯彻算法以贪⼼法选取未被处理的具有最⼩权值的节点,然后对其的出边进⾏松弛操作;⽽贝尔曼-福特算法简单地对所有边进⾏松弛操作,共|V | − 1次,其中 |V |是图的点的数量。
在重复地计算中,已计算得到正确的距离的边的数量不断增加,直到所有边都计算得到了正确的路径。
这样的策略使得贝尔曼-福特算法⽐迪科斯彻算法适⽤于更多种类的输⼊。
贝尔曼-福特算法的最多运⾏O(|V|·|E|)次,|V|和|E|分别是节点和边的数量)。
贝尔曼-福特算法与迪科斯彻算法最⼤的不同:bellman-Ford算法可以存在负权边,⽽dijkstra算法不允许出现负权边;bellman-Ford算法的步骤: 步骤1:初始化图 步骤2 :对每⼀条边进⾏松弛操作 步骤3:检查负权环procedure BellmanFord(list vertices, list edges, vertex source)// 该实现读⼊边和节点的列表,并向两个数组(distance和predecessor)中写⼊最短路径信息// 步骤1:初始化图for each vertex v in vertices:if v is source then distance[v] := 0else distance[v] := infinitypredecessor[v] := null// 步骤2:重复对每⼀条边进⾏松弛操作for i from1 to size(vertices)-1:for each edge (u, v) with weight w in edges:if distance[u] + w < distance[v]:distance[v] := distance[u] + wpredecessor[v] := u// 步骤3:检查负权环for each edge (u, v) with weight w in edges:if distance[u] + w < distance[v]:error "图包含了负权环"View Code题意:John在N个农场之间有path与wormhole ,path+时间,wormhole-时间;求是否存在某点满⾜,John 旅⾏⼀些 paths和wormholes,回到原点时间为负。
bellmanford算法例题

bellmanford算法例题Bellman-Ford算法例题Bellman-Ford算法是一种用于解决带有负权边的图中单源最短路径问题的经典算法。
它可以应用于各种场景,如网络路由、货物配送等。
本文将通过一个例题来介绍Bellman-Ford算法的原理和应用。
假设有一个有向图G,其中包含了n个顶点和m条边。
我们的目标是找到一个顶点s到其余所有顶点的最短路径。
在这个图中,存在负权边,因此Dijkstra算法不适用。
现在我们将使用Bellman-Ford算法来解决这个问题。
首先,我们需要定义一些符号和变量:- n:图G中的顶点数- m:图G中的边数- dist[1..n]:存储顶点s到各个顶点的最短路径长度的数组- edges[1..m]:图G中的边集合,每条边包含两个顶点和其权重接下来,我们来具体描述Bellman-Ford算法的实现过程:1. 初始化:将dist数组中除了起点s的其他元素均设为无穷大,将起点s的dist值设为0。
2. 进行n-1次迭代:- 对于图G中的每一条边(u, v, w),其中u是起点,v是终点,w 是边的权重,我们进行松弛操作(relaxation):- 如果dist[u] + w < dist[v],则更新dist[v]的值为dist[u] + w。
3. 最后,我们再进行一次迭代,检查是否存在负权环路(negative cycle)。
如果在这一次迭代中,仍然可以进行松弛操作并更新dist数组的值,则说明存在负权环路。
接下来,我们通过一个例题来演示Bellman-Ford算法的应用。
假设有如下图所示的有向图G:```5 1(s) ────►(B)────►(C)──▲───2──▲ │10│ │3 │4──▼──5───▼ ▼(E) ─────────►(D)2```我们的目标是求解顶点s到其他顶点的最短路径。
首先,我们初始化dist数组:- dist[s] = 0- dist[B] = ∞- dist[C] = ∞- dist[D] = ∞- dist[E] = ∞接下来,我们进行n-1=4次迭代,对图G中的每条边进行松弛操作:- 第一次迭代:- dist[B] = min(dist[B], dist[s] + 5) = min(∞, 0 + 5) = 5- dist[E] = min(dist[E], dist[s] + 10) = min(∞, 0 + 10) = 10- 第二次迭代:- dist[C] = min(dist[C], dist[B] + 1) = min(∞, 5 + 1) = 5- dist[D] = min(dist[D], dist[C] + 4) = min(∞, 5 + 4) = 9- 第三次迭代:- dist[D] = min(dist[D], dist[C] + 4) = min(9, 5 + 4) = 9- 第四次迭代:- 无需更新最后,我们进行一次迭代来检查是否存在负权环路:- dist[D] = min(dist[D], dist[C] + 4) = min(9, 5 + 4) = 9由于在这次迭代中,dist数组的值没有更新,说明不存在负权环路。
算法导论-单源最短路径习题解

算法导论-单源最短路径习题解24.1-5 设G=(V,E)为⼀带权有向图,其权函数w: E->R。
请给出⼀个O(VE)时间的算法,对于每个顶点v 属于V,找出值δ*(v) =min{δ(u,v)},u属于V。
解: 1. 对每个顶点,令d[v] = 0。
(初始情况,如果没有负权边,则δ*(v) = 0) 2. ⽤Bellman-ford算法,计算d[v],得d[v] = δ*(v)。
简单证明:设δi(u,v)为从u到v边个数不超过i的路径的最⼩值。
δ*i (v) = min{δi(u,v)},u属于V。
则有δ*(v) = δ*n-1(v)。
可以数学归纳法证明d[v] <= δ*i(v)。
显然d[v] <= δ*0(v) = 0。
假设在Bellman-ford 算法前i次迭代中 d[v] <= δ*i(v) 成⽴,u为所有与v相邻的顶点。
对第i+1次迭代,如果δ*i+1(v) = δ*i(v),则d[v]<= δ*i(v)恒成⽴,否则在此轮中边[u,v]被松弛,所以有d[v] = min{d[u] + w[u,v]} <= min{δ*i(u) + w[u,v]} = δ*i+1(v)。
所以有d[v] <= δ*n-1(v),⼜d[v]为两顶点间路径长,所以有d[v] = δ*n-1(v)。
24.1-6 假定⼀加权有向图G=(V,E) 包含⼀负权回路。
请给出⼀个能够列出此回路上的顶点的⾼效算法,并证明你的算法的正确性。
解:Bellman-ford 算法,如果发现d[v] > d[u] + w[u,v],则点u,v处于⼀个负权回路中,此时可以通过寻找前驱顶点得到负权回路。
时间复杂度O(VE)。
24.2-4 给出⼀个⾼效算法来统计有向⽆回路图中的全部路径数。
分析所给出的算法。
解: 对图进⾏拓朴排序,然后按照拓朴排序的逆顺序计算N[u],其中N[u] = sum{N[v]}, [u,v]是所有以u为出发点的边。
单源最短路问题

单源最短路问题(SSSP问题)单源最短路问题指的是该顶点至所有可达顶点的最短路径问题.约定:从start到点i的距离为d[i]。
如果d[i]==INF,说明start和i不连通。
(1) Dijkstra算法! [邻接矩阵]Dijkstra算法是贪心算法。
它只适用于所有边的权都大于0的图。
它的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想),直到扩展到终点为止。
基本思想通过Dijkstra计算图G中的最短路径时,需要指定起点s(即从顶点s开始计算).此外,引进两个集合S和U。
S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。
操作步骤(1)初始时,S只包含起点s;U包含除s外的其他顶点,且U中顶点的距离为"起点s到该顶点的距离"[如,U中顶点v的距离为(s,v)的长度,然后s和v不相邻,则v的距离为∞]。
(2)从U中选出"距离最短的顶点k",并将顶点k加入到S中;同时,从U中移除顶点k。
(3)更新U中各个顶点到起点s的距离。
之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。
(4)重复步骤(2)和(3),直到遍历完所有顶点。
代码:时间复杂度:O(n2)bool visited[N]; // 是否被标号int d[N]; // 从起点到某点的最短路径长度int prev[N]; // 通过追踪prev可以得到具体的最短路径(注意这里是逆序的)void Dijkstra(int start){// 初始化:d[start]=0,且所有点都未被标号memset(visited, 0, sizeof(visited));for (int i=0; i<n; i++) d[i]=INF;d[start]=0;// 计算n次for (int i=0; i<n; i++){int x, min=INF;// 在所有未标号的结点中,选择一个d值最小的点x。
Bellman_ford算法

Bellman-Ford算法思想Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题。
对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数w是边集 E 的映射。
对图G运行Bellman-Ford算法的结果是一个布尔值,表明图中是否存在着一个从源点s可达的负权回路。
若不存在这样的回路,算法将给出从源点s到图G的任意顶点v的最短路径d[v]。
Bellman-Ford算法流程分为三个阶段:(1)初始化:将除源点外的所有顶点的最短距离估计值d[v]←+∞, d[s] ←0;(2)迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)(3)检验负权回路:判断边集E中的每一条边的两个端点是否收敛。
如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在d[v]中。
算法描述如下:Bellman-Ford(G,w,s) :boolean //图G ,边集函数w ,s为源点1 for each vertex v∈V(G)do //初始化1阶段2 d[v]←+∞3 d[s] ←0; //1阶段结束4 for i=1 to |v|-1 do //2阶段开始,双重循环。
5 for each edge(u,v)∈E(G) do //边集数组要用到,穷举每条边。
6 If d[v]> d[u]+ w(u,v) then //松弛判断7 d[v]=d[u]+w(u,v) //松弛操作2阶段结束8 for each edge(u,v)∈E(G) do9 If d[v]> d[u]+ w(u,v) then10 Exit false11 Exit true下面给出描述性证明:首先指出,图的任意一条最短路径既不能包含负权回路,也不会包含正权回路,因此它最多包含|v|-1条边。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
时间复杂度
算法复杂度为O(VE) 其中V=顶点数,E=边数
我们知道Dijkstra的算法复杂度是O(V^2),经 过优化的Dijkstra算法可以达到O((V+E)logE)
所以Bellman-Ford算法并不比它快,但实际上 Bellman-Ford算法也是可以优化的
列可以用双向队列,也可以两个普通队列 初始时将源加入队列。每次从队列中取出一个
元素,并对所有与他相邻的点进行松弛,若某 个相邻的点松弛成功,则将其入队。直到队列 为空时算法结束。
SPFA算法的效率
时间复杂度一般认为是O(kE) 其中k是一个较大的常数,不好估计,但是可
以看出SPFA算法效率应当是很高的 经验表明Dijkstra算法的堆优化要比SPFA快,
Bellman-Ford算法的核心思想——松弛 Dist[u]和Dist[v]应当满足一个关系,即
Dist[v]<=Dist[u]+w[u,v] 反复的利用上式对Dist数组进行松弛,如果没
有负权回路的话,应当会在有限次松弛之后结 束。那么上限是多少次呢?
Bellman-Ford算法思想
考虑对每条边进行1次松弛的时候,得到的实 际上是至多经过0个点的最短路径,对每条边 进行两次松弛的时候得到的是至多经过1个点 的最短路径,……
问题的转化
问题要求输出至少有多少个整点 如果用数组S[i]表示在[0,i]这个区间上面有多少
个点,则题中输入数据ai,bi,ci可以表示为 S[bi]-S[ai-1]>=ci 除此之外还有隐含条件: S[i+1]-S[i]>=0 S[i+1]-S[i]<=1 可以建立一个图,利用Bellman-Ford算法求解
i指向j,权值为k,这样就把差分约束系统问题 转化为最短路径问题了,然后利用BellmanFord算法求解
与Bellman-Ford算法对比
差分不等式组可能是没有解的,这实际上就对 应了Bellman-Ford求解存在负权回路
根据具体情况,有的时候要求的是单源最长路 径,道理是一样的
POJ 1201 Intervals
A
1
-1
1
B
E
F
-1
-1
C -1
D
-∞
Dijkstra算法的局限性
如果利用Dijkstra算法求解,结果为……
标记点A,Dist[B]=-1,标记点B
Dist[C]=0,标记点C
Dist[D]=-1,标记点D
Dist[E]=-2,标记点E
Dist[F]=-1,标记点F
所求得的距离 并不是最短的
与Bellman-Ford算法对比
前面用到过Dist[v]<=Dist[u]+w[u,v]在最短路径 求解后应当总是成立的,可以转化为
Dist[u]-Dist[v]>=-w[u,v] 这与前面的不等式约束Xi-Xj>=-k很类似,因此
可以做如下转化: 如果存在约束条件Xi-Xj>=-k,则建立一条边由
如果边权为负值,Dijkstra算法还正确吗?
求解右图A 至其他点的最短距离
算法步骤:
1)标记点A 2)Dist[C]=2最小,标记点C 3)Dist[B]=3最小,标记点B 结束
B
3
-2
但是ShortestDist[C]=1AC2源自Dijkstra算法的局限性
下图中,A至F的最短路径长度是多少?
A
1
-1
1
B
E
F
-1
-1
C
-1
D
错误结果的原因
Dijkstra的缺陷就在于它不能处理负权回路: Dijkstra对于标记过的点就不再进行更新了, 所以即使有负权导致最短距离的改变也不会重 新计算已经计算过的结果
我们需要新的算法——Bellman-Ford
Bellman-Ford算法思想
Bellman-Ford算法基于动态规划,反复用已有 的边来更新最短距离
但SPFA比普通的Dijkstra算法快。而SPFA算 法可以处理负权的问题,而且比Dijkstra算法 的堆优化的代码要容易实现,因此SPFA是一 个很好的算法。
Exercise
POJ 1511 Invitation Cards 可以用SPFA算法
POJ =
差分约束系统
X0=0 X0-X1>=-1 X1-X2>=-5 X2-X3>=-3 求X1,X2,X3最小值 X1=1,X2=6,X3=9 求解差分不等式组有什么好的方法吗?
在区间[0,50000]上面有一些整点
输入数据 5 373 8 10 3 681 131 10 11 1
含义 有5组约束条件(至多50000) 区间[3,7]上至少有3个点 区间[8,10]上至少有3个点 区间[6,8]上至少有1个点 区间[1,3]上至少有1个点 区间[10,11]上至少有1个点
Bellman-Ford算法 与差分约束系统
单源最短路径问题
单源最短路径=Single Source Shortest Path, 即在有向图(或无向图)中求解给定点到其他 点之间的最短距离
我们已知的方法是…… Dijkstra算法 暑期集训的时候已经对该算法做过介绍,这里
不再重复
Dijkstra算法的局限性
如果没有负权回路,那么任意两点间的最短路 径至多经过n-2个点,因此经过n-1次松弛操作 后应当可以得到最短路径
如果有负权回路,那么第n次松弛操作仍然会 成功,这时,最短路径为-∞
Bellman-Ford算法流程
所有点i赋初值Dist[i]= +∞ ,出发点为s, Dist[s]=0
for k=1 to n-1 for 每条边(u,v) 如果d[u]!= +∞ 且d[v]>d[u]+w[u,v] 则d[v]=d[u]+w[u,v]
Bellman-Ford算法的优化
在没有负权回路的时候,至多进行n-1次松弛 操作会得到解,但实际上可能不到n-1此松弛 操作就得到最优解了
可以在每一轮松弛的时候判断是否松弛成功, 如果所有的边都没有松弛的话,说明BellmanFord算法已经可以结束了
进一步的优化——SPFA算法
SPFA=Shortest Path Faster Algorithm 也即Bellman-Ford算法的队列优化,这里的队