基础图论
1. 最短路
Floyd
- 求多源最短路径
- O(n ^ 3)
- dp[k][i][j]=min(dp[k−1][i][j],dp[k−1][i][k]+dp[k−1][k][j]) ,顶点 i 到 j 且经过顶点 k 的最短路径长度。
Dijkstra
- 求单源最短路径
- 堆优化后为 O((m + n) log n) 近似为 O(m log n)
- 每次选择一个未访问过的到已经访问过的所有点的集合的最短边,再用这个点进行更新
SPFA
- 求单源最短路径
- O(nm)
- 每次取队首 u,根据边 (u, v) 松弛点 v 的最短路,若更新则将 v 加入队列末尾
(dis[v] <-> dis[u] + c(u, v))
2. 最小生成树(一个图的生成树要包含这个图的所有顶点)
Kruskal
- O(m log n)
- 将顶点分为若干个集合,每次选取不在集合内部的最小的边,不断的将各个集合连接起来。
简单的说就是先按边排个序,然后遍历每条边,判断边的两个顶点是否在同一集合中(并查集)。
拓展:次小生成树
- O(n ^ 2)
先求最小生成树 T,枚举添加不在 T 中的边,则添加后一定会形成环。找到环上边值第二大的边(T 中的最大边),把它删掉,计算当前生成树的权值。
- 实现:首先求最小生成树 T,然后从每个结点遍历最小生成树 T,用一个二维数组 max[a][b] 记录结点 a 到结点 b 的路径上边的最大值(即最大边的值)。然后枚举不在 T 中的边 (u, v),计算 T - max[u][v] + w(u, v) 的最小值,即为次小生成树的权值。O(n ^ 2 + e)
3. Tarjan 算法的应用
强连通分量
- 安利一个炒鸡棒的 博客(๑•̀ㅂ•́)و✧
O(V + E)
dfn[u] 表示进入节点 u 时的时间。
low[u] 表示由节点 u 开始搜索所能到达的点中,在搜索树上是 u 的祖先(可以通过一条反祖边或者横叉边到达的节点 v 并且 同样从 v 也要能到达 u)且 dfn 最小的节点的 dfn
(1) 节点 u 通过树边到达节点 v(第一次访问到)
- low[u]=min(low[u],low[v])
(2) 节点 u 通过反祖边到达节点 v,或者通过横叉边到达节点 v(非第一次访问到)
- low[u]=min(low[u],dfn[v])
割点
对于一个搜索树上的非根节点 u,如果存在子节点 v,满足 low(v) >= dfn(u),则 u 为割点
(low(v) >= dfn(u) 的意义是 v 无法向上到达 u 的父节点)对于根节点,如果它有两个或更多的子节点,则它为割点。
割边
- 对于一个搜索树上的节点 u,如果存在子节点 v,满足 low(v) > dfn(u),则 (u, v) 为割边
(low[v] > dfn[u] 时,表示 v 节点只能通过该树边 (u, v) 与 u 连通)
- 对于一个搜索树上的节点 u,如果存在子节点 v,满足 low(v) > dfn(u),则 (u, v) 为割边
4. 二分图基础
匈牙利算法
- 二分图最大匹配
- 增广路:对于一条路径,从一个未匹配点出发,走交替路,终止于另一个未匹配点 ,则这条交替路称为增广路。
- O(nm)
- 尝试更改配对关系,递归回溯。