目录
- 1.广度优先搜索及其扩展应用
1.1 广度优先搜索
参见基本的图算法
1.2 分支限界法
参见分支限界法——对解空间的一种策略搜索(广度优先搜索)
1.3 最小生成树的Prim算法
参见最小生成树
1.4 单元最短路径的SPFA算法
参见最短路径专题
1.5 单元最短路径的Dijstra算法(类似于Prim和分支限界法)
参见最短路径专题 - 2.深度优先搜索及其扩展应用
2.1 深度优先搜索
参见基本的图算法
2.2 拓扑排序
参见基本的图算法
2.3 有向无环图中的单源最短路径问题——按拓扑排序进行松弛
参见最短路径专题
2.4 最大流的前置重贴标签算法(有向无环图的许可网络的拓扑排序)
参见最大流
2.5强连通分量
参见基本的图算法
2.6 回溯法
参见回溯算法——对解空间(搜索树)的一种策略搜索(深度优先搜索) - 3.使用深度优先搜索或广度优先搜索的算法
3.1 最大流FORD-FULKERSON算法
参见最大流
3.2 0/1背包问题
参见0/1背包问题——动态规划、回溯、分支限界法对比
3.3 旅行商问题
参见旅行商(TSP)问题专题——多种方法对比
1.广度优先搜索及其扩展应用
1.1 广度优先搜索
- 广度优先搜索的特点:算法始终是沿着 已发现结点和未发现结点边界 的广度方向向外扩展。
即算法需要在发现所有距离源节点s为k(k条边)的所有结点之后,才会发现距离源节点s为k+1的其他节点。 - 结点分为三类:
白色:开始时都涂为白色
黑色:所有与黑色结点邻接的结点都已被发现
灰色:其邻接结点中可能存在未被发现的白色结点。(是已知和未知两个集合之间的边界。) - 执行广度优先搜索的过程中,将构造出一棵以s为根的广度优先树。
-
队列Q中管理灰色结点集
- BFS的运行时间:
1)每个结点入队和出对最多一次,总时间为O(V)
2)对每个结点进行邻接链表扫描(最多一次),因此扫描邻接链表的时间为O(E)
总时间为O(V + E)
1.2 分支限界法
- 在分支限界法中,每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点(广度优先搜索)。在这些儿子结点中,导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被加入活结点表中。
然后,从活结点表中取下一节点(优先队列中最大或最小值)成为当前扩展结点,并重复上述扩展过程。这个过程一直持续到找到所需的解或活结点表为空时为止。 - (分支限界法的本质)因此,如果算法找到了一个耗费为c的解,并且有一个部分解,它的耗费至少是c,那么就不会有该部分解的扩展生成。
1.3 最小生成树的Prim算法
- 集合A是一棵树,每次加入到A中的安全边永远是连接A和A之外某个节点的边中权重最小的边。
- 广度优先搜索的思想——当从Q中取出一个点u时,即要检查u的所有相邻的点,并更新相关的点。
- Prim算法与分支限界法类似,利用广度优先搜索和优先队列思想,只不过是没有使用分支限界思想。因为可以证明贪心选择性质,使之可以组成一个最优解。
1.4 单元最短路径的SPFA算法
- 建立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。
1.5 单元最短路径的Dijstra算法(类似于Prim和分支限界法)
- 要求所有边的权重为非负值。
- 算法维持集合S,从源节点s到该集合中每个结点之间的最短路径已经被找到。
算法重复从结点集V-S中选择最短路径估计最小的结点u,将u加入到集合S,然后对所有从u发出的边进行松弛。
2.深度优先搜索及其扩展应用
2.1 深度优先搜索
- (回溯)只要可能,就在图中尽量“深入”。
深度优先搜索总是对最近才发现的结点v的出发边进行搜索,直到该节点的所有出发边都被发现为止。一旦结点v的所有出发边都被发现,搜索则回溯到v的前驱结点,来搜索该前驱结点的其他出发边。
该过程一直持续到从源节点可以达到的所有结点都被发现为止。 -
前驱子图:Gπ = (V, Eπ),其中:
Eπ = {(v.π, v): v∈V且v.π ≠ NIL }
深度优先搜索的前驱子图形成一个由多棵深度优先树构成的深度优先森林。森林Eπ中的边称为树边。
深度优先搜索的前驱子图可能由多棵树组成,因为搜索可能从多个源节点重复进行。 -
结点分为三类:
白色:开始时都涂为白色
黑色:其邻接链表被扫描完成后变为黑色。
灰色:其邻接结点中可能存在未被发现的白色结点。(是已知和未知两个集合之间的边界。)
该方法可以保证每个结点仅在一棵深度优先树中出现,因此,所有的深度优先树是不相交的。 - 每个结点盖上时间戳:
1)v.d:记录结点v第一次被发现的时间(涂上灰色的时候)
2)v.d:对v的链接链表完成搜索扫描的时间(涂上黑色的时间)
结点v在v.d之前是白色,在v.d和v.f之间为灰色,在v.f之后是黑色。
- 运行时间:
DFS-VISIT被调用的次数刚好为一次,只有当u为白色的时候,才调用。Θ(V)。
遍历邻接遍历总共执行的是Θ(E)。
总共Θ(V + E)
2.2 拓扑排序
- 使用深度优先搜索对有向无环图进行拓扑排序
- (拓扑排序)对于一个有向无环图G = (V, E)来说,其拓扑排序是G中所有结点的一种线性次序,该次序满足如下条件:
如果图G包含边(u ,v),则结点u在拓扑排序中出于结点v的前面(如果G含有回路,则不可能排出一个线性次序)。
- 拓扑排序的本质是:按照其完成时间的逆序被排成从左至右的一条水平线。所有的有向边都是从左指向右。
拓扑排序正确的本质是:使用深度优先搜索不产生后向边(因为是无环的)。
2.3 有向无环图中的单源最短路径问题——按拓扑排序进行松弛
- 根据结点的拓扑排序来对带权重的有向无环图G=(V, E)进行边的松弛的操作,便可以在Θ(V + E)时间内计算出从单个源节点到所有结点之间的最短路径。
拓扑排序:有向无环图包含从结点u到结点v的一条路径,则u在拓扑排序的次序中位于v的前面。
- DAG——Directed Acyclic Graph有向无环图
2.4 最大流的前置重贴标签算法(有向无环图的许可网络的拓扑排序)
-
维持一个链表L,该表由V-{s, t}中的所有结点构成。
关键性质是,链表L中的结点均按照许可网络里面的拓扑排序次序存放。(许可网络是一个有向无环图)
2.5强连通分量
(强连通)如果一个有向图中任意两个顶点互相可达,则该有向图是强连通的。有向图的强连通分量是“相互可达”关系下顶点的等价类。
有向图G = (V, E)的强连通分量是一个最大结点集合 C包含于V,对于该集合中的任一对结点u和v来说,路径 u ->...-> v和v ->...-> u同时存在,也就是u和v可以互相可达。(转置GT)寻找连通分量的算法需要用到图G=(V, E)的转置,将其定义为GT = (V, ET)
ET = {(u, v): (v, u) ∈ E}
ET是由图G中的边进行反向而获得的。
图G和GT的强连通分量是完全相同的(算法)在Θ(V + E)时间使用使用两次深度优先搜索来计算有向图G = (V, E)的强连通分量。这两次搜索一次运行在G上,一次运行在GT上。
-
第二次实际上是以拓扑排序的次序来访问分量图中的结点。
-
算法的关键:对GT的深度优先搜索访问任意一个强连通分量时,从该连通分量发出的所有边只能是通向已经访问过的强连通分量。
2.6 回溯法
参见回溯算法——对解空间(搜索树)的一种策略搜索(深度优先搜索)
回溯法按词典序考虑笛卡尔积X1 × X2 × ... × Xn 。
(开始)算法最初从空向量开始,然后选择X1中最小的元素作为x1,如果(x1)是一个部分解,算法通过从X2中选择最小的元素作为x2继续,如果(x1, x2)是一个部分解,那么就包括X3中最小的元素,否则x2被置为X2重的下一个元素。
(一般情况)假定算法已经检测到为(x1, x2, ..., xj),它然后考虑向量v = (x1, x2, ..., xj, xj + 1),有以下情况:
1.如果v表示问题的最后解,算法记录下它作为一个解,在仅希望获得一个解时终止,或者继续去找出其他解。
2.(向前步骤)。如果v表示一个部分解,算法通过选择集合Xj+2中的最小元素向前。
3.如果v既不是最终解,也不是部分解,则有两种子情况
3-1.如果从集合Xj+1中还有其他的元素可选择,算法将xj + 1置为Xj+1中的下一个元素。
3-2.(回溯步骤)。如果从集合Xj+1中没有更多的元素可选择,算法通过将xj置为Xj中的下一个元素回溯;如果从集合Xj中仍然没有其他的元素可以选择,算法通过将xj-1置为Xj-1中的下一个元素回溯,依次类推。回溯法也可以对界进行估算,也可以对每个Xi的按照大小排序,所以回溯法与分支限界法在限界上没什么不同。
只不过是在搜索解空间树的方式不一样。
3.使用深度优先搜索或广度优先搜索的算法
3.1 最大流FORD-FULKERSON算法
- (while循环次数)一个简单的上界分析:假设所有的容量都是整数(有理数可以通过乘以系数转换成整数)。假设f*是一个最大流,则while循环最多执行|f*|次。因为流量值每次迭代中最少增加一个单位。
(每次循环找到一条增光路径的时间)给定网络G的一个流f,残存网络Gf中的边由网络G'中所有满足条件cf(u, v) > 0的边(u, v)所构成。因此使用深度优先搜索或者广度优先搜索,在一个残存网络中找到一条路径的时间为O(V+E') = O(E)。
因此整个FORD-FULKERSON算法运行的时间为O(E|f*|)