Drainage Ditches【究极最大流算法之ISAP】(Improved Shortest Augmeng Path)

题目链接(一道模板的最大流问题)


  我们都知道,Dinic算法求最大流的时候,每次都是需要去重新跑一遍分层图,那么现在有没有什么不需要再这样一次又一次地跑一遍分层图的做法呢?

  我们知道,其实每次改变的深度是不多的,所以由这里去进行优化,于是有了ISAP这个只需要跑一次分层图的算法。

时间复杂度上界是O(N^{2} * M),但是随机数据的时候就跑的飞快了!也就是上界比较的松了。

  Improved Shortest Augmeng Path 简称ISAP算法,改善最少增加的路径。

  ISAP的做法是,我们利用BFS求出分层图(仅需要一次),dfs来实现多路增广,dfs退出的时候,说明了目前可以增广的路径已经增广完了。因为残余网络的增广会使得原先的边变成反向,这样就会使得每次bfs的时候得到的点的编号都会是递增的(保证了单调性)。也就是说,我们经过N次这样的操作,一定是可以结束算法的。

  这样,如果目前情况已经没法继续增广了,我们可以试着去调整它们的高度来进行继续增广。

  最开始,我们逆向BFS一次。

  初始化,给所有点的距离标号都赋值为0,然后从T开始,deep[T] = 1,从它开始(不考虑流的权值的)往回跑到起点S,并且更新deep,由于是bfs跑的,所以保证了最开始的deep是最小的。

  这里加入一个gap优化,gap[]数组记录每一层有多少个点,如果说出现了断层,那么显然是不存在新的增广路了。此时结束算法。

if(!(--gap[deep[u]])) deep[S] = N + 1;
while(deep[S] <= N) ret += aug(S, S, T, INF);

  也就是说,当deep[S] > N的时候我们会结束算法。

  在增广的过程中,如果一个点的标号没有被修改过,那么它已经遍历过的边不需要再遍历一次,所以我们存下每次遍历到的哪条边,下一次从这条边开始遍历。因为有可能到这里之后流量用完了,但是后面还没有增广完。

for(int i=head[u], v; ~i; i=edge[i].nex)
{
    v = edge[i].to;
    if(deep[u] == deep[v] + 1)
    {
        int tmp = aug(v, S, T, min(FLOW, edge[i].flow));
        flow += tmp; FLOW -= tmp; edge[i].flow -= tmp; edge[i ^ 1].flow += tmp;
        if(!FLOW) return flow;
    }
}

  并且,最短路的修改具有连续性,前面也说到了一开始得到的deep一定是最小的(每个点都是),并且一定是线性增加的,那么,我们不需要每次再去跑一遍分层图了,而是可以直接给标号加一。

++gap[++deep[u]];
cur[u] = head[u];

  当流量用完之后就可以退出算法了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 205;
int N, M, head[maxN], cnt;
struct Eddge
{
    int nex, to, flow;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), flow(c) {};
}edge[maxN << 1];
inline void addEddge(int u, int v, int w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, int w) { addEddge(u, v, w); addEddge(v, u, 0); }
struct ISAP_MaxFlow
{
    int gap[maxN], cur[maxN], deep[maxN], que[maxN], ql, qr;
    inline void clear(int S, int T)
    {
        for(int i=1; i<=N; i++)
        {
            gap[i] = deep[i] = 0;
        }
        ++gap[deep[T] = 1];
        for(int i=1; i<=N; i++) cur[i] = head[i];
        que[ql = qr = 1] = T;
        while(ql <= qr)
        {
            int u = que[ql++];
            for(int i=head[u], v; ~i; i=edge[i].nex)
            {
                v = edge[i].to;
                if(!deep[v])
                {
                    ++gap[deep[v] = deep[u] + 1];
                    que[++qr] = v;
                }
            }
        }
    }
    inline int aug(int u, int S, int T, int FLOW)
    {
        if(u == T) return FLOW;
        int flow = 0;
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(deep[u] == deep[v] + 1)
            {
                int tmp = aug(v, S, T, min(FLOW, edge[i].flow));
                flow += tmp; FLOW -= tmp; edge[i].flow -= tmp; edge[i ^ 1].flow += tmp;
                if(!FLOW) return flow;
            }
        }
        if(!(--gap[deep[u]])) deep[S] = N + 1;
        ++gap[++deep[u]]; cur[u] = head[u];
        return flow;
    }
    inline int Max_Flow(int S, int T)
    {
        clear(S, T);
        int ret = aug(S, S, T, INF);
        while(deep[S] <= N) ret += aug(S, S, T, INF);
        return ret;
    }
} isap;
inline void init()
{
    cnt = 0;
    for(int i=1; i<=N; i++) head[i] = -1;
}
int main()
{
    while(scanf("%d%d", &M, &N) != EOF)
    {
        init();
        for(int i=1, u, v, w; i<=M; i++)
        {
            scanf("%d%d%d", &u, &v, &w);
            _add(u, v, w);
        }
        printf("%d\n", isap.Max_Flow(1, N));
    }
    return 0;
}
发布了723 篇原创文章 · 获赞 892 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104058761
今日推荐