图论--最大流 Dinic

此生再无相见时 提交于 2019-11-28 13:50:45

最大流:源点到汇点的流量最大

Dinic基本思想:

  1. bfs广搜实现查找多条增广路(可能可以增加流量的路),构建一张层次图。
  2. 在bfs找到增广路的前提下多次dfs深搜进行增广直至所有已查找到的增广路用完

优化:当前弧优化:

  在每次更新完的层次图中(即每一次bfs完后),dfs每增广完一条路之后,该路的价值就已可以看作用尽了,没有必要在之后的dfs中再次深搜该路。故记录下用完价值的边的下一条边,下一次的dfs直接从该边开始,这样就避免了不必要的增广。

/*
普通图的情况下:复杂度O(V2 E)
二分图下的复杂度:O(根号(VE))
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxv = 10004, maxe = 200004;
/*cap 为边的容量 */
struct Edge {
    int next, to, cap;
}e[maxe];
int head[maxv], cnte = 1;
int level[maxv], cur[maxv];
int n, m;

inline bool min(const int& a, const int& b) { return a<b? a:b; }

inline void add_edge(int from, int to, int cap) {
    cnte += 1;
    e[cnte].next = head[from], e[cnte].to = to, e[cnte].cap = cap;
    head[from] = cnte;

    //反向边, 初始的容量为0
    cnte += 1;
    e[cnte].next = head[to], e[cnte].to = from, e[cnte].cap = 0;
    head[to] = cnte;
    return;
}

//bfs分层找增广路,建立层次图
bool bfs(int s, int t) {
    memset(level, 0, sizeof(level));
    queue<int> q;    while(q.size()) q.pop();
    level[s] = 1;
    q.push(s);
    while(q.size())
    {
        int now = q.front(); q.pop();
        for(int i=head[now]; i; i=e[i].next)
        {
            //有容量且没有被标记
            if(level[e[i].to]==0 && e[i].cap > 0) {
                level[e[i].to] = level[now]+1;
                q.push(e[i].to);
            }
        }
    }

    //终点的level大于0说明存在增广路
    return level[t] > 0;
}

//增广流量
//in 为源点输入到这个点上的最小边权
//now 收到的支持,不一定真正能够用到
//@return 真正的输出流量
/** dfs的意义为到达now时传进的最大流量 */
int dfs(int now, int t, int in) {
    if(!in || now==t)
        return in;

    //i为cur[now]的引用-->cur[now]随着i改变
    for(int& i=cur[now]; i; i=e[i].next) {
        int nv = e[i].to;
        if(level[nv]==level[now]+1 && e[i].cap>0)
        {
            // out为点now经边i流向nv的流量
            int out = dfs(nv, t, min(in, e[i].cap)); //一路上都受到最小流量的限制
            if(out > 0) {
                e[i].cap -= out;
                e[i^1].cap += out; //反向边,用于反悔
                return out;
            }
        }
    }
    return 0; //没有增广路,返回0
}

//注意是两个while,每次bfs找到多个增广路后
//多次dfs计算网络中所有增广路的流量
int dinic(int s, int t) {
    int max_flow = 0;
    while(bfs(s, t))
    {
        //每次建立完层次图之后记录当前弧
        for(int i=1; i<=n; ++i)
            cur[i] = head[i];
        int tmp=0;
        while(tmp = dfs(s, t, 0x3f3f3f3f))
            max_flow += tmp;
    }
    return max_flow;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!