ISAP 允许弧 GAP 当前弧优化

#include
using namespace std;
//https://www.mina.moe/archives/6704 优化解释的网址
const int N = 1000;
const int INF = 100000000;
struct Edge
{
    int from,to,cap,flow;
    Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};

struct ISAP
{
    int n,s,t; //n顶点 s->t
    vector<Edge>edges;
    vector<int>G[N];
    //bool S[N];//最小割 最大流流经点集
    //bool T[N];//未流经点集
    bool vis[N]; //bfs扫过 联通的点
    int d[N],cur[N]; //d 到汇点的距离 cur 当前弧下标
    int p[N],num[N];//比Dinic算法多了这两个数组,p数组标记父亲结点,num数组标记距离d[i]存在几个

    void init(int n)
    {
        this->n = n;
        edges.clear();
        for(int i = 0; i <= N; i++)
        {
            //S[i] = 0;
            d[i] = 0;
            //T[i] = 1;
            G[i].clear();
        }
    }
    void addedge(int from,int to,int cap)
    {
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));
        int m=edges.size();
        G[from].push_back(m-2); //正向边
        G[to].push_back(m-1); //反向边
    }

    void bfs()//逆向进行bfs
    {
        memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(t);
        d[t]=0;
        vis[t]=1; //bfs扫过
        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.from]&&e.cap>e.flow) //未满流 正向边
                {
                    vis[e.from]=1; //bfs扫过
                    d[e.from]=d[x]+1; //更新深度
                    q.push(e.from);
                }
            }
        }
    }

    int Augumemt()
    {
        int x=t,a=INF; //x 汇点  a 残量值
        while(x!=s)//找最小的残量值
        {
            Edge&e=edges[p[x]]; //父边
            a=min(a,e.cap-e.flow); //更新残量
            x=e.from; //退回一位
        }
        x=t; //
        while(x!=s)//增广
        {
            edges[p[x]].flow+=a; //更新边的flow
            edges[p[x]^1].flow-=a;//更新反向边
            //S[x] = 1;
            //T[x] = 0;
            x=edges[p[x]].from;
        }
        //S[s] = 1;
        return a;
    }

    int Maxflow(int s,int t)//根据情况前进或者后退,走到汇点时增广
    {
        int flow=0;
        bfs();
        memset(num,0,sizeof(num));
        for(int i=0;i<n;i++)
            num[d[i]]++; //更新d[i]的数量
        int x=s; //从源点开始
        memset(cur,0,sizeof(cur));
        while(d[s]<n)
        {
            if(x==t)//走到了汇点,进行增广
            {
                flow+=Augumemt();
                x=s;//增广后回到源点
            }
            int ok=0; //是否可以前进
            for(int i=cur[x];i<G[x].size();i++) //cur 从上次处理的弧下标开始 当前弧优化
            {
                Edge&e=edges[G[x][i]];
                if(e.cap>e.flow&&d[x]==d[e.to]+1) //允许弧保证最短路
                {
                    ok=1; //可以前进
                    p[e.to]=G[x][i];//记录来的时候走的边,即父边
                    cur[x]=i; //更新弧下标
                    x=e.to;//前进
                    break;
                }
            }
            if(!ok)//走不动了,撤退
            {
                int m=n-1;//如果没有(允许)弧,那么m+1就是n,即d[i]=n
                // m 残量网络中x 到所有邻接点的d[v]的最小值
                for(int i=0;i<G[x].size();i++)
                {
                    Edge& e=edges[G[x][i]];
                    if(e.cap>e.flow)
                        m=min(m,d[e.to]);
                }
                if(--num[d[x]]==0)break;//如果走不动了,且这个距离值原来只有一个,那么s-t不连通,这就是所谓的“gap优化”
                num[d[x]=m+1]++; //更新距离 更新距离数量
                cur[x]=0; //当前弧清零
                if(x!=s)
                    x=edges[p[x]].from;//退一步,沿着父边返回
            }
        }
        return flow;
    }
}isap;
int n, m;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        isap.init(n);
        for(int i=0;i<m;i++)
        {
            int from,to,cap;
            scanf("%d%d%d",&from,&to,&cap);
            isap.addedge(from,to,cap);
        }
        scanf("%d%d",&isap.s,&isap.t);
        printf("%d\n",isap.Maxflow(isap.s,isap.t));
    }
    return 0;
}

你可能感兴趣的:(随笔)