最大流EK、Dinic、SAP三种算法模板

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tawn0000/article/details/82825290

EK
 

//Max_flow
//@2018/05/02 Wednesday
//EK algorithm [Edmonds Karp] O(V*E^2) O(v^2)
//by Tawn
#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e3;
const int INF = 0x3f3f3f3f;

int n,m; //n - Vertices  m - edges
int pre[maxn]; //record predecesor and sign if it is visited
int cap[maxn][maxn]; //record the capacity of residual network
int flow[maxn]; //record the residual flow from starting vertex to current vertex
queue <int> q;

int bfs(int st, int ed)
{
  memset(pre,-1,sizeof(pre));
  while(!q.empty()) q.pop();
  pre[st] = 0;
  flow[st] = INF;
  q.push(st);
  while(!q.empty())
  {
      int t = q.front();
      q.pop();
      if(t == ed) break;
      for(int i = 1; i <= n; i++)
      {
          if(pre[i] == -1 && cap[t][i] > 0)
          {
              pre[i] = t;
              flow[i] = min(flow[t],cap[t][i]);
              q.push(i);
          }
      }
  }
  if(pre[ed] == -1)  return -1;
  else              return flow[ed];
}


int EK(int st, int ed)
{
    int res = 0; //the augmenting flow
    int sum = 0; //the max_flow
    while((res = bfs(st,ed)) != -1)//argumenting path
    {
        int k = ed;
        while(k != st)
        {
            int f = pre[k];
            cap[f][k] -= res;
            cap[k][f] += res;//reversible edge
            k = f;
        }
        sum += res;
    }
    return sum;
}


int main()
{
   int s,t,c;
   scanf("%d%d",&n,&m);
   memset(cap,0,sizeof(cap));
   for(int i = 0; i < m; i++)
   {
       scanf("%d%d%d",&s,&t,&c);
       cap[s][t] = c;
   }
   int ans = EK(1,n);
   printf("%d\n",ans);
   return 0;
}

Dinic


当前弧优化,维护一个cur数组,放入所有的h[i]];每次dfs的时候用int &i = cur[x];

//Max_flow
//@2018/05/04 Friday
//Dinic  O(n^2 * m)  O(m*3*2)
//by Tawn
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>

using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 200 + 10;
const int maxm = 200 + 10;

int n,m;
int l[maxn];//记录层数
int h[maxn];//链式前向星
int cur[maxn];
int tot = 0;

struct edge
{
  int to;
  int c;
  int next;
  edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
 }es[maxm*2];//记录边 注意是2倍

void add_edge(int u, int v, int c)
{
    es[tot] = edge(v,c,h[u]);
    h[u] = tot++;
}

bool bfs(int s, int t)
{
   memset(l,0,sizeof(l));
   l[s] = 1;
   queue <int> q;
   q.push(s);
   while(!q.empty())
   {
    int u = q.front();
    q.pop();
    if(u == t)  return true;
    for(int i = h[u]; i != -1; i = es[i].next)
        {
         int v = es[i].to;
         if(!l[v] && es[i].c) {l[v] = l[u] + 1; q.push(v);}
        }
   }
   return false;
}

int dfs(int x, int t, int mf)
{
    if(x == t) return mf;
    int ret = 0;
    for(int i = cur[x]; i != -1; i = es[i].next)
    {
      if(es[i].c && l[x] == l[es[i].to] - 1)
      {
        int f = dfs(es[i].to,t,min(es[i].c,mf - ret));
        es[i].c -= f;
        es[i^1].c += f;
        ret += f;
        if(ret == mf) return ret;
      }
    }
    return ret;
}

int dinic(int s, int t)
{
  int ans = 0;
  while(bfs(s,t))
  {
   for(int i = 0; i <= n; i++) cur[i] = h[i];
   ans += dfs(s,t,INF);
   }
  return ans;
}

int main()
{
   while(~scanf("%d%d",&n,&m))
   {
   tot = 0;
   memset(h,-1,sizeof(h));
   int u,v,c;
   for(int i = 0; i < m; i++)
   {
    scanf("%d%d%d",&u,&v,&c);
    add_edge(u,v,c);
    add_edge(v,u,0);//增加反向边
   }
   int ans = dinic(1,n);
   printf("%d\n",ans);
   }
   return 0;   
}

SAP
 

 //Max_flow
    //@2018/05/04 Friday
    //SAP  O(n^2 * m)  O(m*3*2)
    //by Tawn
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <cstring>

    using namespace std;
    const int INF = 0x3f3f3f3f;
    const int maxn = 200 + 10;
    const int maxm = 200 + 10;

    int n,m;
    int head[maxn];//链式前向星
    int tot = 0;

    struct edge
    {
      int to;
      int c;
      int next;
      edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
     }es[maxm*2];//记录边 注意是2倍

    void add_edge(int u, int v, int c)
    {
        es[tot] = edge(v,c,head[u]);
        head[u] = tot++;
    }


    int SAP(int s, int t)
    {
        int numh[maxn],h[maxn],ce[maxn],pre[maxn];
        //numh 记录gap优化的统计高度数量数组,h 距离标号数组,ce 当前弧,pre前驱数组
        int f, ans = 0, u, temp, neck, i; //初始化最大流为0
        memset(h,0,sizeof(h));
        memset(numh,0,sizeof(numh));
        memset(pre,-1,sizeof(pre));
        for(i = 1; i <= n; i++)  ce[i] = head[i];
        numh[0] = n;
        u = s;
        while(h[s] < n)
        {
            //寻找增广路
            if(u == t)
            {
                f = INF;
                for(i = s; i != t; i = es[ce[i]].to)
                {
                    if(f > es[ce[i]].c)
                    {
                        neck = i;
                        f = es[ce[i]].c;
                    }
                }
                for(i = s; i != t; i = es[ce[i]].to)
                {
                    temp = ce[i];
                    es[temp].c -= f;
                    es[temp^1].c += f;
                }
                ans += f;
                u = neck;
            }

            //寻找可行弧
            for(i = ce[u]; i != -1; i = es[i].next)
                if(es[i].c && h[u] == h[es[i].to] + 1)  break;

           //寻找增广路
            if(i != -1)
            {
                ce[u] = i;
                pre[es[i].to] = u;
                u = es[i].to;
            }
            else
            {
                if(!--numh[h[u]]) break; //gap optimization
                ce[u] = head[u];
                for(temp = n, i = head[u]; i != -1; i = es[i].next)
                    if(es[i].c)  temp = min(temp, h[es[i].to]);

                h[u] = temp + 1;
                ++numh[h[u]];
                if(u != s) u = pre[u];//重标号并且从当前点前驱重新增广
            }

        }
        return ans;
    }

    int main()
    {
       while(~scanf("%d%d",&n,&m))
       {
       tot = 0;
       memset(head,-1,sizeof(head));
       int u,v,c;
       for(int i = 0; i < m; i++)
       {
        scanf("%d%d%d",&u,&v,&c);
        add_edge(u,v,c);
        add_edge(v,u,0);//增加反向边
       }
       int ans = SAP(1,n);
       printf("%d\n",ans);
       }
       return 0;   
    }

猜你喜欢

转载自blog.csdn.net/Tawn0000/article/details/82825290