目录
1、一些重要的图相关概念
完全图:若有 n 个顶点的无向图有 n*(n-1)/2 条边, 则此图为完全无向图。有 n 个顶点的有向图有n*(n-1) 条边, 则此图为完全有向图。
生成树:一个连通图的生成树是其极小连通子图,在 n 个顶点的情形下,有 n-1 条边。
2、图的存储表示
邻接矩阵
网络的邻接矩阵
邻接表
还可以自行了解邻接多重表
3、图的遍历与连通性
图的遍历
从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次。
为了避免重复访问,可设置一个标志顶点是否被访问过的辅助数组 visited [ ]。辅助数组visited[ ]的初始状态为 0, 在图的遍历过程中, 一旦某一个顶点 i 被访问, 就立即让visited[i]为 1, 防止它被多次访问。
图的遍历的分类
深度优先搜索(DFS)
广度优先搜索(BFS)
深度优先搜索
模拟的时候一定要思路清晰:最重要的是注意回退的思想。
我对于回退的理解:当走到“尽头”时(即没有下一个可以访问的节点时),沿着之前来的路径返回,先看上一个顶点是否有未访问过的下一个顶点,有的话就访问,没有的话就再看上上个顶点,以此类推。
重复上述过程, 直到连通图中所有顶点都被访问过为止。
广度优先搜索
像波纹一样一圈圈泛开
DFS和BFS的总结(图和树通用)
- DFS由于有回溯这个步骤,因此需要记录"来时路",因此需要使用栈或递归。
- BFS是一层一层 or 一圈一圈进行的,因此需要借助队列。
4、连通分量
- 当无向图为非连通图时,从图中某一顶点出发,利用深度优先搜索算法或广度优先搜索算法不可能遍历到图中的所有顶点,只能访问到该顶点所在最大连通子图(连通分量)的所有顶点。
- 若从无向图每一连通分量中的一个顶点出发进行遍历, 可求得无向图的所有连通分量。
- 例如,对于非连通的无向图,所有连通分量的生成树组成了非连通图的生成森林。
/*确定连通分量的算法*/
template <class T, class E>
void Components (Graph<T, E>& G) {
//通过DFS,找出无向图的所有连通分量
int i, n = G.NumberOfVertices(); //图中顶点个数
bool *visited = new bool[n]; //访问标记数组
for (i = 0; i < n; i++) visited[i] = false;
for (i = 0; i < n; i++) //扫描所有顶点
if (!visited[i]) { //若没有访问过
DFS (G, i, visited); //访问
OutputNewComponent(); //输出连通分量
}
delete[] visited;
}
//只是理解代码思路,具体实现细节并未给出
5、最小生成树
Kruskal算法
一句话总结:每次选最小,能要就要,不能要就扔掉
Prim算法
一句话总结:顶点分成敌我双方两个阵营,每次选两阵营之间最小权重的边,即每次花最小的代价将一个地方成员变成我方成员,直至全部变成我方成员。
两种算法的比较
- prim算法适用于边稠密的网络。
- Kruskal算法适合于边稀疏的情形。
- 注意:当各边有相同权值时,由于选择的随意性,产生的生成树可能不唯一。
6、最短路径
Dijkstra算法
推荐这个视频,非常清楚
一句话总结:是否能通过用已确定的最短路径终点为中转使其他的路径变短。
Floyd算法
这个视频很清楚
一句话总结:有几个顶点就循环几轮,每次以一个新的顶点为中转。
思路要清晰:牢记邻接矩阵第 i 行第 j 列的数字的意义——从第 i 个顶点到第 j 个顶点的距离。
7、活动网络
用顶点表示活动的网络 (AOV网络)
拓扑排序
用边表示活动的网络(AOE网络)
求关键路径
求法稍微有点复杂,但是只要花一点时间理解逻辑也不是很难,王卓老师的这个视频讲得非常细致,很容易理解。
总结:
- 先对每个顶点求最早和最晚时间;
- 再根据公式求每条边的最早和最晚开始时间;
- 最后比对边的最早和最晚开始时间,如果相等,则这件事在关键路径上。