图论问题复习总结
图论梗概:大类上,图的概念(重心,直径,LCA等),最短路,最小生成树,图的连通性(圆方树等),二分图(图的匹配),网络流;杂项上,2-SAT,prufer序列,欧拉回路,矩阵树定理,拆点/边,哈密顿路,树hash,建虚树等。特殊的图:仙人掌,基环树。
图论基础
普及组-提高的知识点,涉及广泛,几道例题如下(口胡的内容都是题目)。
-
差分约束
一般来讲,给出关系\(a\le b\),那么\(a\to b\) 连一个边权为0的边,如果是\(a<b\),那么 \(a\to b\) 连一条边权为1的边,然后类似拓扑的,建超级源点到所有入度为0的点,然后跑最长路,每个点的 \(dis\) 就是它最小的值。如果出现了环,那就自相矛盾而产生无解。
-
kruskal的应用
除了一般的最小生成树,kruskal还能很好的处理一些自定义权的问题。
要求S,T的度数不能超过ds,dt来生成树,那么可以定义一个优先级,针对连着S和T的边来定义优先级1,2(ds大那么连着S的就是1) 来进行kruskal,其它的先随便生成一颗树,然后针对一个生成森林再考虑这些边的连接,如果ds==dt的话,就要跑两次这个过程,一次让S的优先级为1,一次让T的优先级为1,这样的贪心正确性大概可以通过ds大的时候一个森林连S一定不会更劣这样来说。
-
广义/重定义/分层图
分层图,一般来说是点之间有拓扑的关系,然后需要分层来处理,这个时候还可以加上一些最短路的重定义。
求 \(1\to n\) 中把路径边权接成十进制需要的最短路径,这个时候是优先考虑长度再考虑字典序,先bfs预处理一个点到 \(n\) 经过的边数,然后从s出发,每次找这个dis最小的一些点,再在这些点里选择此次字典序最小的一些点,然后再考虑这些点继续向下bfs下去,如果有前导0的话就多考虑一个前导全是0的点,然后从这些点开始就好,还要考虑前导的边数,所以还要记录一个dis_s表示从s走来的边,对于数的大小相等的,比较从s到t的边数。
匹配与网络流
匹配
-
图的匹配
- maximal matching:不能再加边的匹配,不一定是最大匹配
- 最大匹配:边数最多的匹配
- 完美匹配:所有点都在的匹配
- 近似完美匹配:图的点数为奇数,刚好只有一个点不在匹配中,换言之如果没有这个点就是完美匹配
-
二分图的匹配
- 二分图的完美匹配:对于小的那一半,使得所有点都属于匹配
- 霍尔定理:对于小的那一半,如果任选K个点,都有至少K个点和它们相邻(有边),那么一定有完美匹配。或者说在图G中存在一组没有公共点的边使得一端的端点恰好是二分图的一半,它的充要条件是对于小的那一半,如果任选K个点,都有至少K个点和它们相邻(有边)。附:正则二分图(每个点度数相同)一定有完美匹配。
网络流
-
最大流解决二分图最大匹配
- CF510E Fox And Dinner (二分图找环)
考虑将奇数和偶数分成二分图,然后对于和为质数的连边,由于最后要形成一个环,所以对于每个点向源汇点的边的容量为2,而匹配的容量只有1,然后跑最大匹配,最大流是n才能保证可以形成若干个质数相邻环,对于输出方案,对于残留网络的边为0的,可以知道若产生从左到右的匹配,那么正向边为0,否则反向边为0,标记一下已经遍历过的点,每次搞个vector存下这个环即可。
- [Bytedance Camp 2019]Deep in the Ocean(二分图找环)
n个点m条边的无向图,满足每个点度数相等且是偶数。在里面找出一个边的子集,满足每个点的度数是2。
\(n,m\leq 10^5\) 首先这是一个正则图,所以把每个点复制一份然后变成二分图一定存在完美匹配,然后就和上边这道抽环类似,但是这里有一个问题就是无向图(u,v)需要建两次边,所以可能一个点会被走两次,所以考虑把(u,v)只保留一个单向边,由于每个点的度数又都是偶数,所以存在欧拉回路,而欧拉回路一定也是一个正则图(入度==出度),那么保留欧拉回路上的有向边再跑二分图匹配即可,和上道题的匹配方式一样。
-
费用流
-
CF802C Heidi and Library (hard)(区间k覆盖)
每本书买卖存分开考虑,所以每个点拆成入点和出点,以表示购入和卖出,考虑每本书买来费用是 \(c[a[i]]\) ,连边\(s\to i\),容量1,费用\(c[a[i]]\),为了使得一段区间内能够保留这本书,连边\(i\to i+1\)容量\(K-1\),费用0,表示可以传递最多\(K-1\)本书到下个位置,考虑扔掉的时机,保留到下次买这本书时即可让下次不花钱,可以连边\(i-1\to last[a[i]]+n\) ,容量是1,费用是\(-c[a[i]]\),也就是回到上次的扔书点,将这次的费用退回,这里一定要是\(i-1\to last[a[i]]+n\),来表示一个这天才扔掉这本书的回收,然后再从这个先前需要扔掉的位置考虑它的流;剩下的,\(i\to i+n\),建边容量1,费用0,表示当天扔掉,\(i+n \to t\) 容量1,费用0,表示要么扔,要么卖(第二类边回退的过程会带来的卖的费用)。
-
各种不常见图论算法
包括各种神仙构造,最小树形图,k短路,平面图算法,支配树,一般图匹配,拟阵交,保序回归等。(保序回归(2020)和支配树(2021)都是省选里考过的,其中支配树这个让我省选大惊(基本抱玲)...)
这部分除了最小树形图和k短路是学习过的,其它都没有。
杂题
各种知识点,虽然题解较短,但写起来还是蛮长蛮细节的。
-
P2341 受欢迎的牛(tarjan/强连通分量)
考虑对于\(x\to y\) 表示y喜欢x,若存在答案则是入度为0的强连通分量的siz,存在答案应当是只存在一个入度为0的强连通分量且它的siz为n(二者其实互为充要),要注意此图不是树,求siz这种方法需要判断一下一个点的siz是否被记录过。
-
综合应用题——二分+缩点(另类)+克鲁斯卡尔重构树
- 求每个格子能放下的最大正方形记录边长mx ,二分答案即可。
- 把mx相等的联通块缩成一个点
- 跑克鲁斯卡尔重构树,小根堆
- 求每两点的lca,点权即是路径上边权最小值 ,记得除了新建的点,原点的权值是连通块的mx。
-
CF555E Case of Computer Network
一个边双可以定向成一个强连通分量,那么可以缩点边双后忽略强联通,然后只考虑树边,可以树上差分记录向下传递的需求和向上传递的需求,一个s1和一个s2,如果一个点既要向下传递又要向上传递,那么需求是冲突的,就无法定向,否则可以定向,另外如果两点不在同一颗树上也显然不能定向。
错误注意(调了一个多小时):缩完点之后再连边一定要注意一个顺序,要么根据新的编号大小(c[x]<c[y]时连边),要么根据一些位置关系之类的,不然会连重边或者说连错(用并查集也可能出错),上一道题也是这样(无意间避免了)。
-
AGC044B Joker(精妙DFS——费脑题)
设\(d[i][j]\)为点\((i,j)\)能够出来的最少路过的人,那么一开始\(\sum d[i][j]\)是\(n^3\)级别的,这意味着我们精准的修改一定能够让它在\(O(n^3)\)结束,注意到对于一条最短的路径一定是递减的,所以对于一次修改,修改过\(d[x][y]--\)后(注意这里因为递归先修改了),只需要\(d[nx][ny]=d[x][y]+2\)就可以让\(d[nx][ny]\)得到修改,不过还要考虑\((nx,ny)\) 是否被使用过,如果被使用过的话,这个位置就要\(d[nx][ny]=d[x][y]+1\) 才行(也就是说原来(x,y)的代价是等于(nx,ny)的,所以路过这里”如履平地“,用于更新其它点)。简单点,只要一句\(d[nx][ny]+vis[nx][ny]=d[x][y]+2\) 即可(即可继续递归让它--)。
-
旅行者(二进制分组)
感动,终于有一道以前做过的题。用的方法是二进制分组,由于求的是关键点之间两两的最短路,可以考虑分组logn次,根据第i位是0还是1来分组,然后正常建图的同时让S连0组T连1组边权为0,接着跑最短路,dis[T]最短的一次就是最优的答案,原理是最优匹配\((x,y)\)一定有一次不在一组。因为这道题图是有向图,所以还得再来一次S连1组T连0组。二进制分组大概就是要使得最优匹配能够在一次分组中出现。
-
CF1023F Mobile Phone Network(”模拟“最小生成树)
先把边排序,要把所有白边加上去,一开始赋值为0,黑边权值不变的跑一个最小生成树,然后考虑黑边对于白边的覆盖,一个黑边覆盖一段白边的话(跨过\(u\to v\),而\(u\to v\)之间的白边权值还没有被更新),那么对于还没有被更小的黑边覆盖更新的白边,更新为它的权值,先考虑怎样更新,对于一个\(u\to v\),选择较浅的那个暴力跳dep,对于路径上的所有没有赋值的白边都赋值为这个黑边的权值(边权事先存到点上),直接在ans里累计这些边权即可,当然不能每次都暴力跳,所以考虑用并查集来跳跃已经处理过的边,也就是更新一下点的fa,每次跳的时候合并x到fa[x]的并查集上,然后跳到根的fa上去,这样可跳次数会越来越少,总复杂度\(O(nlogn+n\alpha(n))\)
-
ALT(最小割+线段树优化建图)
最大流=最小割=最小点权覆盖集=sum-最大点权独立集。网络流嘛。。就是考建图。
连接\(s\to i\) 容量为1,连接 \(i\to[l,r]\) 容量为∞,连接\([l,r]\to t\) 容量为1。然后最小割就是答案。模拟一下,就是割掉\(s\to i\) 表示给了居民宠物,割掉\([l,r]\to t\) 就是给了守卫宠物,而 \(s\) 流不到 \(t\) 就说明守卫合格了。
其它还有好多题,然而我太菜了搞不了这么多,就只有以上了,退役前不知道还有没有時間再搞搞剩下的。