图论

图论基础术语

  • 欧拉回路,哈密尔顿回路,环,简单环
  • 块(任意两点互相连通),点双通分量(任意两点之间至少有两条路径),边通分量(任意两边之间至少有两条路径)
  • 有向无环图(DAG)
  • 默认有(n)个点,(m)条边

DFS森林

  • Tree Edge指树边
  • Back Edge指连向祖先的边
  • Forward Edge指连向子孙的边
  • Cross Edge指连向树其他分支的边
  • 在无向图中只存在Tree Edge和Back Edge

最短路

SSSP

  • 松弛操作(用一边更新两点之间最短路)
  • Dijkstra,贪心,无负权边(可优先队列优化)
  • Bellman Ford,每个点/边松弛(n-1)次,可以有负权边,所以可以判断负环(可队列优化)
  • 时间复杂度为(O(mn)),优化后可达(O((n+m)log_2n))(SPFA容易被卡成(O(nm)),需谨慎使用

变种

  • 边权是0/1
  • 双端队列,如果是0从头部插入,否则从尾部插入
  • 总长不超过W,正权
  • 使用0~w的桶+链表维护这些点,时间复杂度为(O(m+W))

APSP

  • Floyd算法,动态规划((O(n^3))

    for(int k=1; k<=n; k++) {
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
    
  • Johnson算法(负权)((O(nmlog_2n))

    给每一个点标号标号(h(v)),把每条边((u,v))边权改成(s(u,v)+h(u)-h(v))

    对于s-t的一条路径,不会改变最短路

    从1号点出发跑一遍最短路,记(h(v)=dis(v))

    由不等时可以得到(dis(u)+w(u,v)ge dis(v)),非负,跑Dijkstra

差分约束系统

  • 根据最短路有不等式(div(v)le dis(u)+w(u,v))
  • 恰好存在一个u使得不等式存在

如何判断存在?

  • 对原图求一遍最短路
  • 对原图取反,边权取反,求最长路
  • 标号对应能取到的最值
  • 相同则唯一

最小生成树

  • Prim

  • Kruskal

  • Boruvka

    对于当前状态,有(k)个联通块

    我们考虑每个连通块连出去的边里最小的一条

    也就是考虑(k)条边

    排序,贪心选取

    新的边合并后,会得到新的(p)个连通块

    重复到只剩(1)个连通块

    每一次会至少使连通块数量折半

  • 复杂度为(O(n^2))(O(mlog_2m))

最小瓶颈生成树

  • 使得生成树最大的边权最小
    1. 二分答案,类似找第(k)大值的方法
    2. 跑最小生成树

强连通分量

  • Tarjan

对于每个点,有dfn与low两个值

dfn表示的是它被访问的顺序

low表示的是,它及他后面所有访问的点里通过非树边能够回顾到之前的点的dfn的最小值

显然对于一个强连通分量,存在一个节点dfn=low

节点即为所求

每次剖出多个环的嵌套

割点与桥

  • 考虑dfs树,每条边对应着一个到祖先的路径
  • 非树边打标记,如对于((u,v))这条边,在(u)点打上+1的标记,(v)点打上-1的标记
  • v到v的父亲的树边的覆盖次数为子树标记和
  • 割点同理

双连通分量

  • 点连通度:最小的点集使得删去之后图不连通
  • 边连通度:最小的边集使得删去之后图不连通
  • 如果一个图的点连通度(>1),那么是点双联通的,边同理
  • 双连通分量为图中极大双联通子图

考虑dfs树。每条非树边对应着会祖宗的路径,打上标记

例如边((u,v)),u点+1,v点-1

v到v的父亲的树边覆盖次数为子树内所有标记的和

拓扑排序

每次去掉图中入度为(0)的点,复杂度为(O(n+m))

如果最后不为空集则这个图不为DAG

如果求最小的序列,把队列改成优先队列

二分图

  • 可以分成两部分,每部分无环

  • 等价于该图没有奇环

  • 匈牙利算法:每次找一条增广路

    每次试图给一个新的点找到对象

    对于前面的每一个人,如果没有配偶就配对

    否则我问对面那个女孩子的男友能不能找个别的女孩子

    能的话两人都有女朋友了

2-SAT

  • 一堆变量的二元限制
  • 问是否存在合法的赋值

任何一个强连通分量,所有点必须一个状态

  1. 缩点
  2. 拆点

对于一个点x,新建点x'

x代表取,x'代表不取

所以可以连上否定条件

如果x与x'处于同一个强连通分量,就无解

求拓扑,取一点进答案,这个点的对立面不能去,删掉

输出方案

欧拉回路

  • 求出一条恰好每条边经过一次

  • 充分必要条件

    1. 是强连通分量
    2. 出度等于入度
  • 圈套圈算法

    任选起点,从起点开始dfs,每条边只能走一边,当没有可走时把x压入答案队列,欧拉回路为队列逆序

网络流

Dinic((O(n^2m))

在当前图上从(S)跑到(T)

这样每个人都有一个标号,也就是它属于bfs的第几层

每次找到的点,他的bfs编号都必须上一个点+1,强行分层

然后选一条分层的路作为增广路

例题

  1. 普通快乐的最短路径1

    (n)个点的图,有(m)个关键点

    求关键点之间的最短路径

    (1le kle nle 2cdot10^5\1le mle10^6)

    枚举答案(S)(T)的不同二进制位,把关键点分成两个集合(A)(B)

    (A)(B)大力跑最短路径更新答案即可

  2. 普通快乐的最短路径2

    多组询问求两点最短路

    (1le nle 10^5\0<m-n<100\1le qle10^5)

    先建一棵生成树,对于不在的树上的用BFS向全图跑最短路

    对于询问(x,y),要么就是树上走,要么经过其余点中的某一个,枚举经过哪个,松弛

  3. 普通快乐的最小生成树

    询问那些边一定是在最小生成树上的

    (3le nle 500)

    跑最小生成树,对于每一条边,边权一样即可替换

  4. Boruvka

    任意两点连边的费用是(|a_i-a_j|),求MST

    Boruvka只维护最短边

    对于每一块,用set维护不在块里的点的权值

    然后枚举连通块里的点,比如权值为(x)

    即在set中找(x)相邻的点

    去掉边之间的关系

  5. 普通快乐的关键点

    对于一张有向图,定义(a)是key point当且仅当所有其他点要不能到它,要不它能到它,求所有的key point

    (nle 10^5\mle 10^6)

    缩点,对新图跑拓扑

    考虑i是key point的等价条件是比它拓扑排序后的点它能到,比它拓扑排序前的点能到它

    两个相似,拓扑,取反,再拓扑

    所以只需考虑前半部分

    我们维护每个点的出边里在拓扑序最靠前的序号是多少

    那么判断前面的点能否到i

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

限于本人水平,如果文章有表述不当之处,还请不吝赐教。

原文地址:https://www.cnblogs.com/Sam2007/p/12409133.html