最大流
- 如何理解 FF 算法中“反悔”的操作?
- 假设我有一条反向边 (u, v) ,且有边 (u, u1)、(v, v1)、(v2, v),此时如果有一个大小为 x 的流 a 经过了这条反向边,则意味着:(v, u) 的流量减小 x,且 (u, u1) 的边中有大小 x 的流量的来源变为 a;同时原本从 (v2, v) 汇入 (u, v) 的流中有大小为 x 的流量不再汇入 (v, u),而是进入 (v, v1)。
- 插一个 A* 算法的理解:在 A* 算法中,我们可以视作将整个图提了起来,成为一种邻接链表的形式,每一个节点连接的链表中存储着和其连接着的所有边。那么对于每个结构体单元来说,我们可以将其视为一个 “-·->” 的形状,就是说其是指一条边,存储着以下信息:边指向的节点的序号(在形状中体现为 · )、边的权值和下一条边的指针(在形状中体现为 ->),前两个属于边的信息,后一个则属于链表需要的信息。我们做起点为 h[a] 的遍历,那么遍历到的所有边的起点节点都是 a ,所以我们不需要在结构体单元中存储起点。那么现在我们可以说,将每个结构体单元视为一条边是没有问题的。
- EK 算法流程
- 首先使用 bfs 来寻找增广路,每次 bfs 只找一条路,并在寻找时记录每个节点的前驱(这是为了建立反向边,pre 数组记录的内容是边的指针)。寻找到 t 之后,根据前驱边反向遍历找到的这条路并修改正反边的权值,最后加上 t 的最大流量。
- trick:我们如果在建边的时候同时建立正向边和反向边,并且将第一个边的指针设为2,那么可以保证正向边的指针都是偶数,反向边的指针都是奇数,并且假如我有正\反向边的指针 idx,那么完全可以通过 idx ^ 1 来得到其对应的反\正向边。
费用流
- 对比最大流问题,此类问题会在找增广路时找费用最小的路线,并且多了“退费”的过程。我们依然用上面的例子,走反向边时,意味着 (u, v) 的部分流量会流到其他地方,但是已计入结果的总流量不会变。相应地,这条边上被退流的流量对费用的贡献要被退掉,所以我们需要在反向边上赋一个负的权值,用来退费。
- 我们通过 spfa 找的是单位费用总和最小的路线,每做一次 spfa,就找到了一条增广路,也就是找到了“一道流”,最终图中的总流量是固定的,所以我们才需要每次都找单位权值最小,因为最终的总费用是形似\(flow\_sum(dist_1 + dist_2 +...+ dist_k)\)的。