类别 | 题目 |
并查集 | 261, 323, 684 |
最短路径 | 743 |
最小生成树 | 1135 |
拓扑排序 | 207, 210, 802,310 |
关键路径法 | |
图的遍历 | 133, 332(欧拉路径), 785, 841, 997, 1042, 1306 |
其它 | 959, 1043, 1161, 1267, 444 |
就不贴题目超链接了,可以去请看这里!!!leetcode题目目录!!根据题号找对应题目。
归纳总结:
一、图的遍历(traversing of graph)
1、主要就是dfs(depth-first search)、bfs(breadth-first search)。
2、样例代码,请参考:841. 钥匙和房间
二、并查集(Union-Find)
1、找老大,老大是自己的顶点是该联通域的掌门人。
2、集合的合并,如果一条边的两个顶点老大一样,说明这两个顶点原本就在一个联通域内,该联通域内有环;如果一条边的两个顶点老大不一样,那么就要把他们并到一个集合内。
3、最后,老大的数目决定连通域的个数。
4、样例代码,请参考:684. 冗余连接(并查集)
三、拓扑排序(topological sort)
1、采用邻接表来表示有向图,抽象成:
(1)一个二维数组,里面每一个一维数组存以该索引为顶点的后继顶点。
(2)一个一维数组 in, 来表示每个顶点的入度数目。
2、我们开始先根据输入来建立这个有向图,并将入度数组也初始化好。
3、设置一个stack:
(1)将所有入度为0的点压栈。
(2)从栈中退出栈顶元素输出,并把该顶点引出的所有有向边删去,也就是把它的各个邻接顶点的入度数-1。
(3)将新的入度数为零的顶点再入堆栈。
(4)重复过程(2)-(3),直到栈为空。
4、最后,如果已经输出全部顶点,所有顶点入度数都为0,说明有向图中不存在环;如果没有输出全部顶点,那么剩下的顶点中存在入度不为零的顶点,说明有向图中存在环。
5、样例代码,请参考:207. 课程表(拓扑排序)
四、最小生成树(minimum spanning tree , MST)
方法1: Kruskal算法
1、先了解一下Kruskal算法的步骤:
(1)设一个有n个顶点的连通网络为G(V,E),将所有的边按照权值从小到大排序。
(2)当在G中选择一条具有最小权值的边时,若该边的两个顶点落在不同的连通分量上,则将此边加入到T中;否则,即这条边的两个顶点落在同一个连通分量上,会形成环,则将此边舍去,重新选择下一条权值最小的边;如何判断两个顶点是否落在同一个联通分量上,采用并查集来解决。
(3)如此重复下去,直到所有顶点在同一个连通分量上为止。T就是最小生成树。如果最后T中,不能包含所有顶点,那么就没有办法构成最小生成树。
2、Kruskal算法=一个排序+并查集
3、样例代码,请参考:1135. 最低成本联通所有城市(最小生成树)
方法2: prim算法
1、先了解一下Prim算法的步骤:
(1)设一个有n个顶点的连通网络为G(V,E), T(U, TE)是最小生成树。V中存G的顶点,E中存G的边。U中存T的顶点,TE中存T的边。开始时,V中是全部顶点。U和TE都是空的。
(2)第一次先从V中随便取一个顶点加入到U中。
(3)然后从那些其一个端点已经在U中,另一个端点在U外的所有边中找一条最短的边。并把该边和顶点分别并入TE和U中。如此进行下去,每次往生成树里并入一个顶点和一条边,直到n-1次之后,把所有n个顶点都并入U中,此时U=V,T是最小生成树。如果最后T中,不能包含所有顶点,那么就没有办法构成最小生成树。
2、样例代码,请参考:1135. 最低成本联通所有城市(最小生成树)
五、最短路径(shortest path)
Dijkstra算法(单源最短路径算法):
1、先了解一下Dijkstra算法的步骤:
(1)设一个有n个顶点的连通网络为G, 顶点集合U和T。最开始的时候,U中存G的全部顶点以及源点到这些顶点的路径长度:源点到自身的路径长度是0,源点到不相连的顶点,长度是无穷大。T为空。
(2)每次去U中找出路径最小的顶点uu,在U中删掉uu,并且将uu插入到S中。
(3)在U中遍历从uu出发能到达的所有顶点v,根据U(v)=min(U(v), S(uu)+W[uu,v]),其中W[uu,v])表示uu到v的路径长度,更新一波U(v)的长度。
(4)重复过程(2)-(3),所有顶点都加入了S中。
2、样例代码,请参考:743. 网络延迟时间(最短路径)
Prim算法和Dijkstra算法的对比:
1、相同点:都是基于贪心的思想,都是一开始两个顶点集合A和B,A为空,B为全部顶点,都是从B中选一个加入到A中,直到全部顶点加入完成。
2、不同点
(1)Prim算法:每次从那些其一个端点已经在A中,另一个端点在B中的所有边中找一条最短的边,加入A中。
(2)Dijkstra算法:每次去B中找出路径最小的顶点uu,加入A中。
还多一个步骤:要根据uu更新一波B中的最短路径长度。在B中遍历从uu出发能到达的所有顶点v,根据B(v)=min(A(v), A(uu)+W[uu,v]),其中W[uu,v])表示uu到v的路径长度,更新一波B(v)的长度。
六、关键路径法(Critical Path Method, CPM)
1、先了解一下CPM的步骤,核心就是5个for 循环
Ev[i]表示事件i的最早出现时间,E[i]表示活动i的最早出现时间,Lv[i]表示事件i的最迟出现时间,L[i]表示活动i的最迟出现时间。
以j顶点指向k顶点为例:
(1)从源点开始向汇点递推,根据Ev[k]=max(Ev[j]+w[j,k]),求出Ev数组。其中的最大值Ev[n]是汇点的最早开始时间。
(2)因为汇点就是结束点,其最迟出现时间与最早出现时间相同,即Ev[n]=Lv[n]。将(1)中排好序的事件,从汇点开始向源点递推,根据Lv[j]=min(Lv[k]-w[j,k]),求出Lv数组。
(3)活动的最早开始时间与事件的最早开始时间是一样的,求出E数组,E=Ev.
(4)j顶点指向k顶点,中间经历活动aj, 根据L[j]=Lv[k]-(活动j所需的时间),求出L数组。
(5)E[i]=L[i]的活动,就是关键活动,由这些活动组成的路径就是关键路径。
(6)有可能关键路径不止一条,那么这时候可以将re按照字典序排序,如果后一条路径的起始点,与前一条路径的结束点不一致,即x[i][0]!=x[i-1][1],删后面一条路径。那么此时多一个for循环。
2、样例代码,请参考:图的知识点补充(AOE网络的关键路径)