[普及+] 模板口胡
差分约束系统
省流:给出 \(n\) 个数, \(m\) 个不等式,每个形如 \(x_a-x_b\le w\) ,求通解。
转化一下,\(x_a\le x_b+w\)
这不就是图论点转移吗,连一条 \(x_b\to x_a\) 权值为 \(w\) 的边,最后要求通解即求当前点集权值满足所有边。
不妨这样想,确定一个点,再更新其它点。
这不就是最短路吗。
但是有一个问题,就是可能会选到一个出度为 \(0\) 的点。这样虽然说也能造出合法解,但是不太好。
不妨钦定原点 \(0\) ,并向每个点连边 \(0\to i\) 一条权值为 \(0\) 的边。意思就是 \(x_i\le 0\)。
这样从 \(0\) 开始跑单源最短路即可。
出现负环说明无解,负环的意思就是一个数要小于自己,即 \(x\le x-3\) 明显无解。
因为存在负数边,通常使用 BF 求解。
全正数也可以使用 dij 。
Janson 全源最短路
省流:有负边权,求有向图全源最短路。
因为 \(n\le 3000\) 所以 Floyd 首先排除。
我们想只要用 dij 就可以做到 \(n^2\log n\)
所以这就是一个怎么处理负环。
直接加一个数显然不行。
所以我们定一个原点 \(0\) ,向每个点连一条边权为 \(0\) 的边,算出 \(0\) 到每个点的最短路 \(h_x\) 。
然后给每条 \(u\to v\) 的边加上 \(h_u-h_v\)。
因为 \(h_v\le h_u +w\) 所以 \(h_u-h_v+w\ge 0\)
现在所有边权非负了。
我们考虑一条 \(u\to v\) 的路径,就是 \(w_u+w_{v1}+w_{v2}..+h_u-h_v\) 中间的都被查分掉了、
直接跑 dij 即可。
所以使用 BF 处理和 dij 跑。
感觉号飞舞啊,没什么用。
二维凸包
很简单,一些点,找二维凸包。
And 算法:
先按照 \(x\) 为第一关键字排序,再按 \(y\) 为第二关键字排序。
然后从左往右找下凸包,遇见上凸的就出栈,和斜率优化差不多。
然后再从右往左找上凸包,同理。
随便写写就完事了。
这个还没有下面的难。
注意:
- 注意栈开成两倍空间
欧拉路径
省流:有向联通图的一笔画问题。
第一步:判断是否有解。
需要满足以下条件:
- 所有点出入度都相同(欧拉回路)或只有一点入度比出度多 \(1\) (终点) 且只有一点出度比入度多 \(1\) (起点)
- 图联通
通过简单处理我们可以得到起点。
怎么找一条欧拉路径呢?
首先从起点开始 dfs。
一种显然的思路就是只走一个点,最终就能走完这个图。
这其实是错的。
举个例子:
4 4
1 2
2 3
3 1
3 3
dfs 路线是 \(1\to 2\to 3 \to 1\)
哎? \(3\to 3\) 的自环没走啊!
这是因为,在不是欧拉回路的情况下,对于所有点,会有一条路径是走向终点的,也就是走不回来,而且其它路径随便走,总能走回当前点。
所以,我们的思路是:对于每个点,不断枚举出边。
枚举出边只会执行至多两次,即是否存在终点路径。
因此,我们的想法是先走非终点路径,再走终点路径。
但是这样不好搞,不好判断。
我们这样思考:
如果已经处理完这个点往后走的所有路径,那到这个点怎么办?
很明显,直接往后加上即可。
考虑一个点加上去的条件,即遍历完毕所有路径,如果还有出边,则这个点不会被记录。
那么,如果不存在出边,那么我们就到终点路径了。
可以发现,终点路径总是最后一个走的。所以也是最先被记录了。、
对于非终点路径节点,我们可以根据题目要求任意选择去走。
所以最后倒序输出遍历节点即可。
通俗的说,就是一直走,走到死胡同就记录一下,如果不是死胡同就记录下走过哪些点。
发现死胡同总是最先记录的,倒序就是遍历顺序。
Nim游戏
感觉最难 [普及+] 模板就是这个了。
这个摆了先,后面开个博弈论专题搞一搞。