Dinic+当前弧优化

  Dinic算法是不停用BFS构造层次图,然后用阻塞流增广。

  什么叫层次图呢》假设在残量网络中,起点到结点u的距离为dist(u),那么这个dist(u)看作结点u的层次,只保留每个点出发到下一个层次的弧,得到的图就是层次图。阻塞流是不考虑反向弧时的极大流。最多计算N-1次阻塞流(因为每次沿阻塞流增广后,t相对于s的层次至少增加1),每次阻塞流的计算时间不超过O(MN),因此总时间复杂度为O(N^2M),但实际上比这个快。

  当前弧优化是什么意思呢?注意在DFS中用cur[x]表示当前应该从x的编号为cur[x]的边开始访问,也就是说从0到cur[x]-1的这些边都不用再访问了,相当于删掉了,达到了满流。DFS(x,a)表示当前在x节点,有流量a,到终点t的最大流。当前弧优化在DFS里的关键点在if(a==0) break;也就是说对于结点x,如果x连接的前面一些弧已经能把a这么多的流量都送到终点,就不需要再去访问后面的一些弧了,当前未满的弧和后面未访问的弧等到下次再访问结点x的时候再去增广。

struct Edge{
    int from,to,cap,flow;
};

struct Dinic{
    int n,m,s,t;            //结点数,边数(包括反向弧),源点编号和汇点编号
    vector<Edge> edges;     //边表。edge[e]和edge[e^1]互为反向弧
    vector<int> G[MAXN];    //邻接表,G[i][j]表示节点i和第j条边在e数组中的序号
    bool vis[MAXN];         //BFS使用
    int d[MAXN];            //从起点到i的距离
    int cur[MAXN];          //当前弧下标

    void clear_all(int n){
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }
    void clear_flow(){
        int len=edges.size();
        for(int i=0;i<len;i++) edges[i].flow=0;
    }
    void add_edge(int from,int to,int cap){
        edges.push_back((Edge){from,to,cap,0});
        edges.push_back((Edge){to,from,0,0});
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool BFS(){
        memset(vis,0,sizeof(vis));
        queue<int> q;
        q.push(s);
        d[s]=0;
        vis[s]=1;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            int len=G[x].size();
            for(int i=0;i<len;i++){
                Edge& e=edges[G[x][i]];
                if(!vis[e.to]&&e.cap>e.flow){
                    vis[e.to]=1;
                    d[e.to]=d[x]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int DFS(int x,int a){
        if(x==t||a==0) return a;
        int flow=0,f,len=G[x].size();
        for(int& i=cur[x];i<len;i++){
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
                e.flow+=f;
                edges[G[x][i]^1].flow-=f;
                flow+=f;
                a-=f;
                if(a==0) break;
            }
        }
        return flow;
    }
    int maxflow(int s,int t){
        this->s=s;
        this->t=t;
        int flow=0;
        while(BFS()){
            memset(cur,0,sizeof(cur));
            flow+=DFS(s,INF);
        }
        return flow;
    }
    vector<int> mincut(){   //call this after maxflow
        vector<int> ans;
        int len=edges.size();
        for(int i=0;i<len;i++){
            Edge& e=edges[i];
            if(vis[e.from]&&!vis[e.to]&&e.cap>0) ans.push_back(i);
        }
        return ans;
    }
    void reduce(){
        int len=edges.size();
        for(int i=0;i<len;i++) edges[i].cap-=edges[i].flow;
    }
};


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值