最大流当前弧优化Dinic分层模板

最大流模板:

  • 普通最大流
  • 无向图限制:将无向图的边拆成2条方向相反的有向边
  • 顶点有流量限制:拆成2个点,连接一条容量为点容量限制的边
  • 无源汇点有最小流限制的最大流:理解为水管流量形成循环
  • 有源汇点的最小流限制的最大流
  • 有源汇点的最小流限制的最小流
  • 容量为负数:不能直接利用最大流求边权为负数的最小割。不知道怎么具体处理。。。

模板使用Dinic分层算法,使用了当前弧优化,效率还是不错的,使用的是vector存图,如果使用邻接表存图效率应该会更高吧。

但是ispa算法的效率更高,采用了当前弧优化的ispa算法那就更更高的效率了(=^ ^=),但是这个算法目前不会啊。。。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define PI acos(-1.0)
const int maxn=1e5+100,maxm=1e5+100,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=1e18+7;
struct edge
{
    int from,to,cap,flow;
};
vector<edge>es;
vector<int>G[maxn];
bool vis[maxn];
int dist[maxn];
int iter[maxn];
void init(int n)
{
    for(int i=0; i<=n+10; i++) G[i].clear();
    es.clear();
}
void addedge(int from,int to,int cap)
{
    es.push_back((edge)
    {
        from,to,cap,0
    });
    es.push_back((edge)
    {
        to,from,0,0
    });
    int x=es.size();
    G[from].push_back(x-2);
    G[to].push_back(x-1);
}
bool BFS(int s,int t)
{
    memset(vis,0,sizeof(vis));
    queue <int> Q;
    vis[s]=1;
    dist[s]=0;
    Q.push(s);
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();
        for (int i=0; i<G[u].size(); i++)
        {
            edge &e=es[G[u][i]];
            if (!vis[e.to]&&e.cap>e.flow)
            {
                vis[e.to]=1;
                dist[e.to]=dist[u]+1;
                Q.push(e.to);
            }
        }
    }
    return vis[t];
}
int DFS(int u,int t,int f)
{
    if(u==t||f==0) return f;
    int flow=0,d;
    for(int &i=iter[u]; i<G[u].size(); i++)
    {
        edge &e=es[G[u][i]];
        if(dist[u]+1==dist[e.to]&&(d=DFS(e.to,t,min(f,e.cap-e.flow)))>0)
        {
            e.flow+=d;
            es[G[u][i]^1].flow-=d;
            flow+=d;
            f-=d;
            if (f==0) break;
        }
    }
    return flow;
}
int Maxflow(int s,int t)
{
    int flow=0;
    while(BFS(s,t))
    {
        memset(iter,0,sizeof(iter));
        int d=0;
        while(d=DFS(s,t,inf)) flow+=d;
    }
    return flow;
}

int in[maxn],out[maxn];
int l[maxn];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);

    /**有源汇点*/
    int s,t;
    scanf("%d%d",&s,&t);

    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
    init(n);
    for (int i=1; i<=m; i++)
    {
        int u,v,r;
        scanf("%d %d %d %d",&u,&v,&l[i],&r);
        out[u]+=l[i],in[v]+=l[i];
        addedge(u,v,r-l[i]);
    }

    /**有源汇点有下界*/
    addedge(t,s,inf);

    /**有下界添加新源点0,汇点n+1*/
    int ss=0,tt=n+1;
    int sum=0;
    for(int i=1; i<=n; i++)
    {
        if(in[i]>out[i])
        {
            addedge(ss,i,in[i]-out[i]);
            sum+=in[i]-out[i];
        }
        else if(in[i]<out[i])
            addedge(i,tt,out[i]-in[i]);
    }

    /**无下界直接用s,t求最大流*/
    if(Maxflow(ss,tt)!=sum) puts("NO");
    else
    {
        puts("YES");

        /**有源汇点*/
        int ans=-es[2*m+1].flow;
        es[2*m+1].flow=0;
        es[2*m].flow=0;
        es[2*m].cap=0;
        ans+=Maxflow(s,t);///ans-=Maxflow(t,s);///最小流
        printf("%d
",ans);

        /**无源汇点:可以理解成水管形成循环*/
        for(int i=0; i<m*2; i+=2)
            printf("%d
",es[i].flow+l[i/2+1]);///每根水管的流量情况
    }
    return 0;
}
原文地址:https://www.cnblogs.com/GeekZRF/p/7289716.html