算法课笔记系列(六)—— 图(Part2)

上一周去了一趟说走就走的治疗之旅,所以算法课都没能上。:( 不过,人生有过这样一次,很足够。只要永远做自己认为对的事情就不会有跨不过去的坎。

跟上周一样,这一周的内容包含几个小部分,分别为最短路径动态规划、所有点对之间的最短路径和网络流。

第一部分:最短路径动态规划

对于一个有向图G=(V, E), 每一条边权重为cvw(权重可为负), 问题是找到从节点s到t的最短的路径。如果边的权重中有负值,则Dijkstra方法不适用。因此我们想到一个办法,给每一个权值加上一个正常数使得每一条边的权重都为非负,这个方法也不行。

这里定义一个负(成本)环。如下图所示,顾名思义,所有边的权值的和为负数。

如果一个从s到t的路径中包含一个负(成本)环,那s-t之间不存在最短路径,否则,存在一个最短路径。如下图。

下面用动态规划来解决最短路径的问题。

定义OPT(i, v) 表示使用最多i条边的最短的v到t的路径P。

1) P中使用最多i-1条边

OPT(i, v) = OPT(i - 1, v)

2) P使用第i条边

如果(v, w)是第一条边,那么OPT使用(v, w), 然后选择最佳的w-t路径使用最多i-1条边

通过之前的观察,可以得出,如果没有负环,那么OPT(n - 1, v)为最短的v-t路径的长度。

实现代码如下:

时间复杂度为O(mn), 空间复杂度为O(n^2).

下面提出一种改进。

保持一个矩阵M[v]为我们目前能够找到的最短的v-t路径。除非M[v]在前一个迭代中改变了,否则不需要检查(v, w)形成的边。这里有这样一个定理,在整个算法中,M[v]是v-t路径的长度,在i轮更新之后,M[v]不会大于使用不多于i条边的最短路径的长度。内存消耗为O(m+n),时间复杂度为O(mn)最坏情况,但是实际会更快。

Bellman-Ford实现算法如下:

使用以上算法可以证明,如果对于所有的v有OPT(n, v) = OPT(n - 1, v),那么就没有负环。

如果OPT(n, v) < OPT(n - 1, v), 那么任何从v到t的最短路径都包含一个环W,并且,W包含负数的权值边。

以上两条可以用于检测负环。Bellman-Ford算法的时间复杂度为O(mn), 空间复杂度为O(m+n).

第二部分:所有点对之间的最短路径

最短路径包含单源最短路径问题和所有点对之间的最短路径问题。单源最短路径问题包含非负边权重的Dijkstra算法(O(E+VlgV)),一般算法Bellman-Ford算法(O(VE)) 和 DAG算法一种Bellman-Ford的变化(O(V+E))。所有点对之间的最短路径问题则包括,Dijkstra算法|V|次:O(VE+V2lgV), 和一般方法(下面要介绍的三种算法)。

给出一个图G=(V, E), |V| = n, 边和权重之间的函数关系为w: E→R. 输出为最短路径长度的nxn的矩阵,对于所有的i, j ∈V。

考虑在每一个顶点运行一次Bellman-Ford算法,时间为O(V2E)

动态规划

考虑一个有向图nxn的邻接矩阵,定义为从i到j使用最多m条边的一个最短路径的权重。因为我们得到

对于任意m = 1,2,…,n-1,

要证明以上式子,可以对进行条件松弛,对于任意的k从1到n,如果,那么就将dij更新为

没有负环就意味着,

以下为所有点对之间的一半情况的三种算法:

1. 矩阵乘法

计算C=A · B, 其中C,A和B都为nxn的矩阵,

使用传统的算法需要O(n^3)的时间复杂度。

如果我们将+ 因设为min,将·映射为+, 那么有

这样,

单位矩阵I表示为

(min,+)乘法是关联的,在实数中,它形成了一种集合结构叫做闭合半环。因此,我们可以计算

得出,

时间复杂度为,并不比n倍的Bellman-Ford算法好。

因此,一种改进的矩阵乘法算法是,不停平方,

这样,只需要计算O(lgn)次的平方,

时间复杂度变为

为了检测是否存在负权重环,需要检查对角线是否含有负值需要额外的O(n)的时间。

2. Floyd-Warshall算法

该算法也是一个动态规划,但是有着更快的速度。

定义是从i到j包含集合为{1,2,…k}为中间结点的最短路径的权重

那么有,,且,

寻找最段路径的过程中会发生

循环为

时间复杂度为,并且更加有效。

3. Johnson算法

对每一个v∈V,给定一个标签h(v),重新给每一条边(u, v)∈E赋予权重

这样,相同的两个顶点之间的路径将会被相同的值被重新赋权重。

A.找到一个标记为h的顶点,使得对于所有的(u, v)∈E成立通过使用Bellman-Ford算法来解决不同限制

或者决定一个负权重环是否存在,所需时间为O(VE).

B.对于每一个使用的顶点运行Dijsktra算法,时间复杂度

C.对每一个最短路径长度重新赋权值产生原始图的最短路径长度,时间复杂度为

因此,总的时间为

第三部分 网络流

最大流和最小切割是两个非常常见的算法问题。

最小切割问题:

可以抽象为通过边的材料流动。

有向图G=(V, E)没有平行的边,两个不同的结点s为source,t为sink,c(e)是边e的容量。

定义s-t切割是s∈A,t∈B的V的一个划分(A,B)。cut (A,B)的容量是

因此,最小s-t划分问题就是找到有着最小容量的一个s-t划分。

流的问题则为:

首先定义s-t流是一个满足一下条件的函数:

对于每一条边e∈E:;对于每一个顶点v∈V-{s,t},

流f的值定义为,如下图所示

因此最大流问题就是找到s-t流的最大值。

流值定理为:令f是任意的一个流,(A, B)是任意的s-t cut。那么,通过cut传送的网络流等于总的离开s的量,即

以下为一个形象的例子:

弱对偶性:令f是任意的一个流,(A, B)是任意的s-t cut。那么,流的值最多为cut的容量,即v(f) <= cap(A, B)

推论为:如果v(f) = cap(A, B), 那么f是最大的流,(A, B)是最小的cut

下面使用贪心算法来寻找一个最大流算法:

首先令所有的边e∈E,都有f(e)=0. 找到一条s-t路径P有每一条边f(e) < c(e)。沿着路径P分割流,重复该操作直到无法进行下去。这里无法再进行下去的含义要注意,局部最优并不能够推出全局最优。

下面介绍一种剩余图,

                  

原始的边为e=(u, v)∈E,流f(e), 容量为c(e). 剩余容量定义为

则剩余图为

剩余边有正的剩余容量,因此,

Ford-Fulkerson算法可以用来找到最大流。也称为分割路径算法。

分割路径定理:如果不存在分割路径算法,流f则为一个最大流。

时间: 2024-08-30 06:30:17

算法课笔记系列(六)—— 图(Part2)的相关文章

算法课笔记系列(七)—— 平摊分析

本周的内容是Amortized Analysis,是对算法复杂度的另一种分析.它的基本概念是,给定一连串操作,大部分的操作是非常廉价的,有极少的操作可能非常昂贵,因此一个标准的最坏分析可能过于消极了.因此,其基本理念在于,当昂贵的操作也别少的时候,他们的成本可能会均摊到所有的操作上.如果人工均摊的花销仍然便宜的话,对于整个序列的操作我们将有一个更加严格的约束.本质上,均摊分析就是在最坏的场景下,对于一连串操作给出一个更加严格约束的一种策略. 均摊分析与平均情况分析的区别在于,平均情况分析是平均所

算法课笔记系列(九)——近似算法(Part1)

这一周的内容是近似算法(Approximation Algorithm). 对于许多的问题的算法,我们通常目标在于设计一个可以在多项式时间内运行的算法.然而,上一节的NP问题告诉我们这样的算法不一定存在.近似算法其实是针对NP难问题的一种退让,对于许多P不等于NP的最优化问题,无法在多项式时间内找到最优解.因此,如果可以只求一个我们可以接受的解,而不是非要最优解,那么可能存在一个多项式时间的算法. 因此,这里的"近似"其实就是针对最优化问题而言的.其主要应用也是用来解决最优化的问题,并

算法课笔记系列(八)——NP问题及其计算复杂性

本周的内容是NP问题,NP的全称是Non-deterministic Polynomial,即多项式复杂程度的非确定性问题.百度上对NP的解释是,P/NP问题是在理论信息学中计算复杂度理论里至今没有解决的问题.通俗的说,是将不可知的问题转化为已知的问题,进而计算器复杂度. 首先介绍多项式时间的约减,即Polynomial-Time Reductions,通过解决另一个不同问题的假设的子程序,使用不包含子程序在内的多项式时间来解决一个问题的方法.主观上,一个多项式时间约减证明了第一个问题不比第二个

Java基础复习笔记系列 六 容器

Java基础复习笔记系列之 容器 1. 2.

算法学习笔记(六) 二叉树和图遍历—深搜 DFS 与广搜 BFS

图的深搜与广搜 复习下二叉树.图的深搜与广搜. 从图的遍历说起.图的遍历方法有两种:深度优先遍历(Depth First Search), 广度优先遍历(Breadth First Search),其经典应用走迷宫.N皇后.二叉树遍历等.遍历即按某种顺序訪问"图"中全部的节点,顺序分为: 深度优先(优先往深处走),用的数据结构是栈, 主要是递归实现. 广度优先(优先走近期的).用的数据结构是队列.主要是迭代实现. 对于深搜.因为递归往往能够方便的利用系统栈,不须要自己维护栈.所以通常实

算法学习笔记 二叉树和图遍历—深搜 DFS 与广搜 BFS

图的深搜与广搜 马上又要秋招了,赶紧复习下基础知识.这里复习下二叉树.图的深搜与广搜.从图的遍历说起,图的遍历方法有两种:深度优先遍历(Depth First Search), 广度优先遍历(Breadth First Search),其经典应用走迷宫.N皇后.二叉树遍历等.遍历即按某种顺序访问"图"中所有的节点,顺序分为: 深度优先(优先往深处走),用的数据结构是栈, 主要是递归实现: 广度优先(优先走最近的),用的数据结构是队列,主要是迭代实现: 对于深搜,由于递归往往可以方便的利

算法学习笔记系列——分治法

一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换). 二.基本思想及策略 分治法设计思想:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之. 分治策略是:对于一个规模为n的问题,若该

算法学习笔记系列——动态规划法

一.基本概念 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 二.基本思想与策略 基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息.在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解.依次解决各子问题,最后一个子问题就是初始问题的解. 由于动态规划解决

算法导论笔记——第六七章 堆排序和快速排序

第六章 堆排序 最小堆和最大堆:近似的完全二叉树 A[parent(i)]<=A[i]或者A[parent(i)]>=A[i] 建堆复杂度O(n) 排序O(nlgn) 实际应用中,快速排序一般优于堆排序.可用于优先队列等. 在一个包含n个元素的堆中,所有优先队列的操作均可在O(lgn)时间内完成. 第七章 快速排序 与归并排序一样用分治思想 主元pivot可随机生成