网络流:最大流之SAP算法

网络流主要解决三种问题:最大流、最小流和费用流。

最大流算法主要有三种:EK算法、Dinic算法、SAP算法。

本篇博客是关于SAP算法的。最坏的情况下,SAP算法将达到复杂度O(VE2)。

  1 #include <iostream>
  2     #include <cstdio>
  3     #include <algorithm>
  4     #include <queue>
  5     #include <cstring>
  6  
  7     using namespace std;
  8     const int INF = 0x3f3f3f3f;
  9     const int maxn = 200 + 10;
 10     const int maxm = 200 + 10;
 11  
 12     int n,m;
 13     int head[maxn];//链式前向星
 14     int tot = 0;
 15  
 16     struct edge
 17     {
 18       int to;
 19       int c;
 20       int next;
 21       edge(int x = 0, int y = 0, int z = 0) : to(x), c(y), next(z) {}
 22      }es[maxm*2];//记录边 注意是2倍
 23  
 24     void add_edge(int u, int v, int c)
 25     {
 26         es[tot] = edge(v,c,head[u]);
 27         head[u] = tot++;
 28     }
 29  
 30  
 31     int SAP(int s, int t)
 32     {
 33         int numh[maxn],h[maxn],ce[maxn],pre[maxn];
 34         //numh 记录gap优化的统计高度数量数组,h 距离标号数组,ce 当前弧,pre前驱数组
 35         int f, ans = 0, u, temp, neck, i; //初始化最大流为0
 36         memset(h,0,sizeof(h));
 37         memset(numh,0,sizeof(numh));
 38         memset(pre,-1,sizeof(pre));
 39         for(i = 1; i <= n; i++)  ce[i] = head[i];
 40         numh[0] = n;
 41         u = s;
 42         while(h[s] < n)
 43         {
 44             //寻找增广路
 45             if(u == t)
 46             {
 47                 f = INF;
 48                 for(i = s; i != t; i = es[ce[i]].to)
 49                 {
 50                     if(f > es[ce[i]].c)
 51                     {
 52                         neck = i;
 53                         f = es[ce[i]].c;
 54                     }
 55                 }
 56                 for(i = s; i != t; i = es[ce[i]].to)
 57                 {
 58                     temp = ce[i];
 59                     es[temp].c -= f;
 60                     es[temp^1].c += f;
 61                 }
 62                 ans += f;
 63                 u = neck;
 64             }
 65  
 66             //寻找可行弧
 67             for(i = ce[u]; i != -1; i = es[i].next)
 68                 if(es[i].c && h[u] == h[es[i].to] + 1)  break;
 69  
 70            //寻找增广路
 71             if(i != -1)
 72             {
 73                 ce[u] = i;
 74                 pre[es[i].to] = u;
 75                 u = es[i].to;
 76             }
 77             else
 78             {
 79                 if(!--numh[h[u]]) break; //gap optimization
 80                 ce[u] = head[u];
 81                 for(temp = n, i = head[u]; i != -1; i = es[i].next)
 82                     if(es[i].c)  temp = min(temp, h[es[i].to]);
 83  
 84                 h[u] = temp + 1;
 85                 ++numh[h[u]];
 86                 if(u != s) u = pre[u];//重标号并且从当前点前驱重新增广
 87             }
 88  
 89         }
 90         return ans;
 91     }
 92  
 93     int main()
 94     {
 95        while(~scanf("%d%d",&n,&m))
 96        {
 97        tot = 0;
 98        memset(head,-1,sizeof(head));
 99        int u,v,c;
100        for(int i = 0; i < m; i++)
101        {
102         scanf("%d%d%d",&u,&v,&c);
103         add_edge(u,v,c);
104         add_edge(v,u,0);//增加反向边
105        }
106        int ans = SAP(1,n);
107        printf("%d
",ans);
108        }
109        return 0;   
110     }
原文地址:https://www.cnblogs.com/St-Lovaer/p/11909244.html