图论
图论算法一般都是揉在一起的,很难单独把算法拆开讲,所以直接上题目吧。分类是大致分的,其实有很多是交叉的。
二叉树
二叉树的遍历有三种,分别为前序遍历,中序遍历和后序遍历,并且给定其中的两种遍历能够求出另一种遍历 (必须已知中序遍历)。
前序遍历:按 根 左 右 的顺序进行;
中序遍历:按 左 根 右 的顺序进行;
后序遍历:按 左 右 根 的顺序进行。
最短路 & 生成树
算法复杂度
- 多源最短路Floyd:严格 $O(n^3)$
- 单源最短路Dijkstra:
-
- 朴素:严格 $O(n^2)$
-
- 优先队列优化:均摊 $O((e+n) \log n)$
- Bellman-Ford:
-
- 最多松弛 $n-1$ 次
-
- 严格 $O(ne)$
- SPFA:
-
- 即队列优化Bellman-Ford
-
- 最坏 $O(ne)$,最好 $O(1)$
板子
咕咕咕
如何卡掉 SPFA
见 https://www.zhihu.com/question/292283275/answer/484871888
P1967 货车运输
最大生成树,然后跑LCA
1 |
|
P1073 最优贸易
分层图,最短路
1 |
|
P1119 灾后重建
很重要的题目,考察了 Floyd的本质。
Floyd
用 $dis[k][i][j]$ 表示 i 和 j 之间可以通过编号为 $1\dots k$ 的节点的最短路径,显然,$dis[0][i][j]$ 就是原始邻接矩阵数据。
状态转移方程:
$$
dis[k][i][j]=min(dis[k-1][i][j],dis[k-1][i][k]+dis[k-1][k][j])
$$
Floyd 的本质其实就是DP,只不过我们通常做题时利用了数据只会使用一次性的原理,把 dis 变成滚动数组,减少了一维,节省空间。
更多请见 https://www.cnblogs.com/fangwencai/p/4784914.html。
1 | //提前将邻接矩阵存在 dis 数组里,其他不连通的地方初始化成无穷大 |
只要我们能够利用 DP 特性,就能解决许多问题
再回来看这道题,文中说每个村子是不同时间修好的,而每个节点都按顺序给出,这不就是恰好相当于 Floyd的中间点吗?我们可以把 k轮 DP分开做,每输入一个点,就用这个点当中转站把最短距离更新一遍,也就是跑一遍 DP。
Code:
1 |
|
判负环
转自 @SingerCoder,%lgh
注意一定要判入队次数而不是松弛次数。
hack原理很简单:如果存在重边导致了多次松弛,那么对松弛次数的判断就会产生影响。解决方式就是判入队次数,虽然略慢,但是更稳。
Update[2020.7.26]:在写差分约束的时候想用spfa判无解,然后经过一系列的思考就有了下面这组新的hack数据:
1 | input: |
注意这组hack只对用链式前向星(而非vector)存边且判的是松弛次数(而非入队次数)的有效,而且该数据无重边无自环,比discuss里面的那个数据更有说服力。
首先hack原理就是对n号节点进行n-1轮松弛,每轮都有 $x( x \in [1,n-1])$ 次松弛,这样就能产生 $n^2$ 级别的松弛次数。
但是判入队次数就hack不掉了,每轮的第一次松弛会让n节点入队,但n节点只有在下一轮才会出队;因此本轮的其余所有松弛全部无法导致入队。
P3385 [模板]负环
1 |
|
基环树
n 个点 n 条边 只有一个环 枚举断边