图算法总结1(图的遍历及应用、并查集)[代码没有写]

来源:互联网 发布:网络棋牌室违法吗 编辑:程序博客网 时间:2024/06/01 08:27

图的表示

图常见有两种表示方法:邻接表和邻接矩阵。

图的遍历

深度优先搜索(DFS)O(V+E)
DFS

广度优先搜索(BFS)O(V+E)
BFS

深度优先搜索的应用

1:找出图中的所有连通分量?
答:1)无向图(连通分量):在上述DFS伪代码中,在函数DFS(G) line:7退出时,下一个vertex将从另一个联通分量开始,
所以,我们可以加个数组id[V], 表明每个vertex所属的连通分量即可。
2)有向图(强连通分量):可以运行两遍DFS来求得强连通分量。
概念:the transpose of G(见下图)

伪代码见下图,解释如下:
Line 1:对图G运行DGF,求得finish times;
Line 2:求图G的转置;
Line 3:以finish times的降序对G的转置图的vertex进行DFS。

2:判断图是否有环(一般指有向图)?
答:此题有两种方法:
1)拓扑排序,如果有拓扑排序,则说明此图没有环,否则有环。
2)DFS(它可以用来拓扑排序),题目等价于找反向边。在DFS_VIsit(G,u) line:5,如果vertex的颜色为GRAY时(BLACK不算),就说明存在环。
3:判断无向图是否是二部图?
答:加入color[V]数组,并在遍历的时候给vertex着色(两种颜色),如果成功,则是二部图。
4:JVM的垃圾回收机制
答:如右图所示,垃圾是指没有用的资源,由JVM负责回收,那么可以对每个资源进行标记,标记完后看哪个资源没有没有被标记并回收。
还有一种方法是ref计数,当引用时ref+=1,当不需要时ref-=1,如果ref==0,则释放这个资源,但这种方法要防止出现死锁状态。
garbage collection
5:模式匹配(KMP等等。。。)
答:这个暂时还没看,后面补上。。。抱歉!
6:有向图的拓扑排序
答:当DFS遍历到某条路径的最后一个顶点,因此DFS回退序列就是拓扑排序的逆序列, DFS_Visit()
补充:拓扑排序的另一种方法就是寻找入度为0的node,并删除这个node,再更新每个node的入度,迭代。
如果在某次迭代过程中,找不到入度为0的node,则说明存在环。

广度优先搜索的应用

1:走迷宫(POJ3984)
2:连连看游戏(编程之美p88)
3:倒酒问题:一个8L杯子装满了酒,有一个3L的空杯子和5L的空杯子,问怎样才能用最少的次数倒出4L的酒?
答:将三个酒杯中酒的数量当做状态,初始状态为(8,0,0),每个酒杯的容量限制为(8,3,5),则对当前三个酒杯的状态转移(这是关键)进行穷举(BFS),
直到某个酒杯的酒的数量为4为止(见下图)。

4:过桥问题:四个人夜间过桥,只有一根火把,每次最多过两个,过桥必须带火把,
他们的过桥速度分别是1min,2min,5min,10min,如何在最快的时间内让四个人过桥?
答:此题和上题思路差不多,都是状态转移。代码详见(http://blog.csdn.net/zhouweiabc/article/details/29604951)

并查集:Disjoint sets

这部分参考:http://www.cnblogs.com/cyjb/p/UnionFindSets.html。
它主要应用于不相交集合的合并问题。一些常见的用途有求连通子图、求最小生成树的 Kruskal 算法及Prim算法和求最近公共祖先
(Least Common Ancestors, LCA)等。
对集合{s1,s2,s3,,,,sk},确定一个集合的代表(可以是此集合中的任意一个元素),对并查集的基本操作有三个:
  1. Make-Set(n):建立一个新的并查集,其中包含 n 个单元素集合。执行n次。
  2. Union(x, y):把元素 x 和元素 y 所在的集合合并,要求 x 和 y 所在的集合不相交,如果相交则不合并。至多执行n-1次。
  3. Find-Set(x):找到元素 x 所在的集合的代表,该操作也可以用于判断两个元素是否位于同一个集合,只要将它们各自的代表比较一下就可以了。
Disjoint sets的常见操作
disjoint operation
1)基于链表的集合表示方法

如上图(a)所示,这个表示方法,每个元素指向头节点(此节点为这个集合的代表),head指向首节点,tail指向尾节点,则Make-Set(s)时间复杂度为O(s),Find-Set(x)时间复杂度为O(1)。

Union(x, y)(见上图(b))如果按照上图这种方法来union的话,总时间为O(n^2),union共被调用2n-1次,所以平均为O(n)。
这里有个启发式(weighted-union heuristic)的方法,每次union的时候,将小集合合并到大集合,则时间复杂度会变小。

2)基于森林的表示方法(Disjoint-set forests)


如图所示,这种方法Union(x, y)时间复杂度为O(1),而Find-Set(x)时间复杂度就变高了。但是我们可以用“union by rank”和"path compression"这两种启发式方法是森林尽可能对称,从而Find-Set(x)时间复杂度保持很低。

所谓“union by rank”,和上面的“weighted-union heuristic”类似,每个vertex保持一个rank(这个node的最大高度),当union时,将rank小的node合并到rank大的node上。


所谓"path compression",见上图,当我们Find-Set(a)时,当从a遍历到f的过程中,改变每个node的parent,从而减少每个node的rank。

伪代码见下图


0 0
原创粉丝点击