《算法》图笔记
动态连通性问题(Dynamic Connectivity)
- union-find算法
- quick-find
- 初始时各点的连通分量各不相同;
- 每添加一条边,则检测两点是否属于同一个连通分量;
- 若属于,则不做处理,因为不影响连通性;
- 若不属于,则合并这两点所在的连通分量。
- quick-union
- 每添加一条边,则检测两点所在树的根节点是否相同;
- 若相同,则不做处理;
- 若不相同,则某一根节点指向另一根节点
- 每添加一条边,则检测两点所在树的根节点是否相同;
- weighted-quick-union
- 记录每棵树的大小,每次合并时,总将小树合并到大树
- quick-find
- 最优算法
- 在weighted-quick-union的基础上,压缩路径,开销接近于常数
- 例如,自己想的办法,在find的root时候,将点s直接链到root上
这是一类无向图问题
深度优先搜索(DepthFirstSearch)
广度优先搜索(BreadthFirstSearch)
连通分量(Connected Components)
- 用深度优先搜索实现//代码TODO
- 用union-find算法实现//代码TODO
检测环(Circle Detection)
- 如果顶点v的邻接点w已经被标记,且不是v的父顶点u的话,那必然有另外一条路先于v标记了w,即既有经过v的路径s->w,又有不经过v的路径s->w,即构成了环 //代码TODO
双色问题
-
如果顶点v的邻接点w已经被染色,且与v同色,则不是一个双色图,即二分图。
-
符号图(Symbol Graphs) //代码TODO
-
间隔的度数(Degrees Of Separation) //代码TODO
这是一类有向图问题
有向无环图(DAG)
- 进行有向环检测确保的确无环;
- 有向无环图才可以进行拓扑排序;
有向环检测
- 若顶点v的邻接顶点w已经被标记,且还在调用栈里面,即既存在v->w边,也间接存在一条w->v边,这两者构成一个环,注意去无向的区别
拓扑排序(topological sort)
- 就是有向图的逆后序
- 优先级调度
- 无环有向图的最短路径问题
- //代码TODO
强连通性(Strong connectivity)
- Kosaraju算法
Kosaraju算法(Kosaraju–Sharir algorithm)
- 计算一个图G的反向图的逆后序排列
- 按照前述顺序进行DFS
- 一个DFS中被访问到的点属于同一个强连通分量。
顶点对的可达性(All-pairs reachability) 传递闭包(transitive closure)
这是一类加权无向图问题
最小生成树(Minimum Spanning trees)
- Prim算法
- Kruskal算法
Prim算法
- 从一个点开始,将权重最小的横切边添加进树,直到树有V-1个边 //延时实现TODO
- 在树生长的过程中,点v可能有多条边与树相连,我们只要知道最短那条边就好了//非延时实现TODO
Kruskal算法
- 从最小边开始,从不会构成环的相邻边中挑选最小边添加进树,直到树有V-1个边 //TODO
这是一类加权有向图问题 最短路径
边的松弛(Edge relaxation)
顶点的松弛(Vertex relaxation)
Dijkstra算法:将距离s最近的非树顶点放松并加入树中,如此这般,直到所有的顶点都在树中或者所有的非树顶点离s无限远。
若该图是无环的,则按照拓扑顺序放松顶点,就能解决最短路径问题 //TODO
最长路径问题//TODO
关键路径(Critical Path)
- 优先级限制下的并行任务调度 //TODO
- 相对最后期限下的并行任务调度 //TODO
若不存在负权重环,则
- Bellman-Ford算法
- 以任意顺序放松有向图的所有边,重复V轮//TODO
- 基于队列的Bellman-Ford算法
- 基于上轮放松过的顶点本轮才可能放松的认识,优化算法 //TODO
负权重环的检测
- 套汇 //TODO
当且仅当一副含有V个顶点的图G满足下列5个条件之一时,它就是一棵树:
- G有V-1条边且不含有环;
- G有V-1条边且是连通的;
- G是连通的,但删除任意一条边都会使它不再连通;
- G是无环图,但添加任意一条边都会产生一个环;
- G中的任意一对顶点之间仅存在一条简单路径。
二分图(bipartite graph)是一种能够将所有顶点分为两个集合的图,每条边依附(incident)的两个顶点分属两个不同的集合。
生成树(spanning tree)是一棵含有图所有顶点的树,生成树森林是所有连通分支 (connected components)的生成树的集合。
解决任务调度类应用通常需要以下3步:
- 指明任务和优先级条件
- 不断检测并去除有向图中的所有环,以确保存在可行方案
- 使用拓扑排序解决调度问题
深度优先搜索(DepthFirstSearch)是这样一种算法:
- 在访问一个顶点时,
- 将它标记为已访问;
- 递归地访问它的所有没有被标记过的相邻(adjacent)顶点。
他可以被用来:
- 无向图
- 寻找单源路径(single-source paths)//代码TODO
- 寻找图中所有的连通分量//代码TODO
- 检测环//代码TODO
- 双色问题(Two-colorability)//代码TODO
- 有向图
- 单源可达性(Single-source reachability)//代码TODO
- 单点有向路径(DepthFirstDirectedPaths)//代码TODO
- 有向环检测(Directed cycle detection)//代码TODO
- 拓扑排序
- Kosaraju算法//代码TODO
广度优先搜索(BreadthFirstSearch)是这样一种算法:
- 先将起点加入队列,然后重复下列步骤直到队列为空,
- 取队列的下一个顶点v并标记它;
- 将与v相邻的所有未被标记过的顶点加入队列。
他可以被用来:
- 无向图
- 寻找单源最短路径(single-source shortest paths)//代码TODO
- 确定间隔的度数(Degrees of separation)//代码TODO,用符号图来实现
- 有向图
- 单点最短有向路径(BreadthFirstDirectedPaths)//代码TODO