网络最大流:Dinic

0.前置知识

存图方式(邻接表邻接矩阵),图的遍历(dfsbfs

1.引入

我们举个例子吧:
有一个水管工,叫超级吗力熬,他会造水管,有一天他造了一个水管网络,展现出来的形式就像一个图。其中有一个点只有出边,是用来输入水的,还有一个点只有入边,是用来输出水的。点之间有一些管子,这些管子都有各自单位时间内的容量,现在超级吗力熬想知道,他的管子在单位时间里最多能流多少水。

2.概念

网络流有一大堆神秘而又阴森的概念。

  • 源点:顾名思义,就是输入水的那个点,一般用s表示
  • 汇点:顾名思义,就是输出水的那个点,一般用t表示。。。
  • 容量:顾名思义。。。一条边单位时间内的的容量
  • 残余网络:进行增广后剩余的网络
  • 増广:

増广就是在残余网络中寻找从源点到汇点的可行路径(増广路),并将该路径上的所有边的容量减去路径中的最小容量,形成新的残余网络
例如:
在这里插入图片描述
如果当前有这样一个残余网络,那么 s 4 1 t s\rightarrow4\rightarrow1\rightarrow t 就是一条増广路,最小容量是4,进行増广过后就形成了这样一张图:
在这里插入图片描述
如何寻找増广路?直接dfs即可。

  • 反向边:

有时候,程序増广的时候会出现爆炸性错误,例如还是那个图:
在这里插入图片描述
有两条増广路,万一程序选错了怎么办?
这时就要请出反向边了。
每次増广的时候,在残余网络上逆着増广路径建容量与増广路径最小容量相等的反向边,比如刚才那张图,就顺着 t 1 4 s t\rightarrow1\rightarrow4\rightarrow s 建容量为4的边。
这就给了程序一个反悔的机会。

3.Dinic的优化

前面的概念讲的好多啊,都把网络流的朴素算法讲完了。。。
Dinic的优化就是他用bfs建立了由s开始的一个分层图,每次寻找増广路时必须让边上的层数严格递增,这样就不会陷入毒瘤数据卡成的死循环,比如这样的著名毒瘤数据:
在这里插入图片描述
在这个数据中,如果用朴素算法,就会让中间容量为1的边上下抖动抽搐,等到他抽了999次的时候才把上面和下面的999减没。如果用Dinic,两次直接求出999+999。

4.代码

404 Not Found(Click for more information) 完结!