网络流算法

标号法过程为:
(1) 先将 flagprev alpha 3 个数组各元素都初始化-1
(2) 将源点初始化为已标号未检查顶点,即 flag[0] = 0, prev[0] = 0, alpha[0] = INFINF 示无穷大;并将源点入队列。
(3) 当队列非空并且汇点没有标号,从队列头取出队列头顶点,设这个顶点为 vv 肯定是已标号未检查顶点;因此,检查顶点 v 的正向和反向“邻接”顶点,如果没有标号并当前可以进行标号,则对这些顶点进行标号并入队列,这些顶点都是已标号未检查顶点;此后顶点 v 为已标号已检查顶点。反复执行这一步直至队列为空或汇点已获得标

测试数据:(6 表示顶点数, 10表示边数!)

6 10  
0 1 8 2
0 2 4 3
1 3 2 2
1 4 2 2
2 1 4 2
2 3 1 1
2 4 4 0
3 4 6 0
3 5 9 3
4 5 7 2

  1 //////// 标号法求网络最大流.
  2 
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 
  7 #define _clr(x, y) memset(x, y, sizeof(x))
  8 #define Min(x, y) (x < y ? x : y)
  9 #define INF 0x3f3f3f3f
 10 #define N 1005
 11 using namespace std;
 12 
 13 struct ArcNode // 弧结构:c表示容量,f表示流量.
 14 {
 15     int c, f;
 16 };
 17 ArcNode edge[N][N];
 18 int queue[N]; // 队列
 19 int flag[N]; // -1表示未检查未访问,0表示已访问未检查相邻顶点,1表示已访问已检查相邻顶点
 20 int pre[N]; // 保存一个点的前驱.
 21 int alpha[N]; //保存一个点的可改进量
 22 int n;
 23 
 24 int abs(int a)
 25 {
 26     return a < 0 ? -a : a;
 27 }
 28 
 29 void ford()
 30 {
 31     while(1)
 32     {
 33         //  初始化,
 34         int front=0, rear=0;
 35         _clr(flag, -1);
 36         _clr(pre, -1);
 37         _clr(alpha, -1);
 38         flag[0] = 0, pre[0] = 0, alpha[0] = INF;
 39         queue[rear++] = 0; // 把源点加入队列
 40         while(front<rear && flag[n-1]==-1) // 队列非空 且 汇点还未标号
 41         {
 42             int v = queue[front++];
 43             for(int i=0; i<n; i++)  // 检查顶点v的相邻顶点
 44             {
 45                 if(flag[i]==-1)  // i点还未访问
 46                 {
 47                     if(edge[v][i].c<INF && edge[v][i].f<edge[v][i].c) // 正向且流量未满
 48                     {
 49                         flag[i] = 0, pre[i] = v;
 50                         alpha[i] = Min(alpha[v], edge[v][i].c-edge[v][i].f);
 51                         queue[rear++] = i;
 52                     }
 53                     else if(edge[i][v].c<INF && edge[i][v].f)  // 反向 且 有流量
 54                     {
 55                         flag[i] = 0, pre[i] = -v;
 56                         alpha[i] = Min(alpha[v], edge[i][v].f);
 57                         queue[rear++] = i;
 58                     }
 59                 }
 60             }
 61             flag[v] = 1;  // 加上源点流出量即是 最大流!
 62         }
 63 
 64         if(flag[n-1]==-1 || alpha[n-1]==0) break; // 汇点无法标号 或 得到的可改进量为0:即没有可改进路.
 65 
 66         // 进行调整后得到残留网络.
 67         int k1=n-1, k2=abs(pre[k1]);
 68         int a = alpha[n-1];
 69         while(1)
 70         {
 71             if(edge[k2][k1].f<INF)  // 正向加上可改进量
 72                 edge[k2][k1].f += a;
 73             else  // 反向减去可改进量
 74                 edge[k1][k2].f -= a;
 75             if(k2==0) break; // 直至到源点.
 76             k1 = k2, k2 = abs(pre[k1]);
 77         }
 78     }
 79 
 80     int MaxFlow=0;
 81     for(int i=0; i<n; i++)
 82         for(int j=0; j<n; j++)
 83             if(edge[i][j].f<INF)
 84             {
 85                 printf("%d->%d: %d
", i,j,edge[i][j].f);  // 输出各条弧的实际流量
 86                 if(i==0)
 87                     MaxFlow += edge[i][j].f;  // 加上源点流出量即是 最大流!
 88             }
 89     printf("MaxFlow: %d
", MaxFlow);
 90 }
 91 int main()
 92 {
 93     int m, a, b, c, f;
 94     while(~scanf("%d%d", &n, &m))
 95     {
 96         for(int i=0; i<n; i++)
 97             for(int j=0; j<n; j++)
 98                 edge[i][j].c=edge[i][j].f = INF;
 99         while(m--)
100         {
101             scanf("%d%d%d%d", &a, &b, &c, &f);
102             edge[a][b].c = c, edge[a][b].f = f;
103         }
104     puts("before test");
105     ford();
106     puts("after test");
107     }
108     return 0;
109 }
View Code

transform: none; white-space: normal;

Dinic
算法的具体步骤为:
(1) 初始化容量网络和网络流;
(2) 构造残留网络和层次网络,若汇点不在层次网络中,则算法结束;
(3) 在层次网络中用一次 DFS 过程进行增广, DFS 执行完毕,该阶段的增广也执行完毕;
(4) 转步骤(2)

#include <cstdio>
#include <cstring>

#define _clr(x, y) memset(x, y, sizeof(x))
#define Min(x, y) (x < y ? x : y)
#define INF 0x3f3f3f3f
#define N 1003
using namespace std;

int edge[N][N];
int queue[N], n;
int dist[N];

// 建立层次图
bool bfs()
{
    _clr(dist, -1);
    int front=0, rear=0;
    dist[1] = 0;
    queue[rear++] = 1;
    while(front < rear)
    {
        int u = queue[front++];
        for(int v=1; v<=n; v++)
        {
            if(dist[v]<0 && edge[u][v])
            {
                dist[v] = dist[u] + 1;
                queue[rear++] = v;
            }
        }
    }
    return dist[n]>0 ? 1:0;
}

// dfs代表一次增广,返回的是本次增广获得的可改进量.0表示没有增广路
int dfs(int u, int low)
{
    int a = 0;
    if(u==n) return low;
    for(int v=1; v<=n; v++)
    {
        //  u.v之间联通且满足层次条件约束且有曾广路存在
        if(edge[u][v] && dist[v]==dist[u]+1 && (a = dfs(v, Min(low, edge[u][v]))))
        {
            edge[u][v] -= a;
            edge[v][u] += a;
            return a;
        }
    }
    return 0;
}
int main()
{
    int m, a, b, c;
    while(~scanf("%d%d", &m, &n))
    {
        _clr(edge, 0);
        while(m--)
        {
            scanf("%d%d%d", &a, &b, &c);
            edge[a][b] += c;
        }
        int ans=0, a=0;
        while(bfs())  // 一直建立层次图,直到无法到达汇点为止.
            while(a = dfs(1,INF))  // 得到一条曾广路的可改进量.
                ans += a;
        printf("%d
",ans);
    }
    return 0;
}

一般预流推进算法

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 #define _clr(x, y) memset(x, y, sizeof(x))
 5 #define Min(x, y) (x < y ? x : y)
 6 #define INF 0x3f3f3f3f
 7 #define N 1005
 8 using namespace std;
 9 
10 int flow[N][N], h[N];
11 int E[N], n, MaxFlow, S, T;
12 queue<int> Q;
13 
14 void Push(int &x)
15 {
16     for(int i=1; i<=n; i++)
17     {
18         int tmp = Min(E[x], flow[x][i]);
19         if(tmp>0 && (x==S || h[x]==h[i]+1))
20         {
21             flow[x][i] -= tmp, flow[i][x] += tmp;
22             E[x] -= tmp, E[i] += tmp;
23             if(i==T) MaxFlow += tmp;
24             if(i!=T && i!=S) Q.push(i);
25         }
26     }
27 }
28 
29 void Push_Relabel()
30 {
31     MaxFlow = 0;
32     S = 1, T=n;
33     _clr(h, 0);
34     _clr(E, 0);
35     E[S]=INF, E[T]=-INF;
36     h[S]=n;
37     Q.push(S);
38     while(!Q.empty())
39     {
40         int x = Q.front();
41         Q.pop();
42         Push(x);
43         if(x!=S && x!=T && E[x]>0)
44         {
45             h[x]++;
46             Q.push(x);
47         }
48     }
49     printf("%d
", MaxFlow);
50 }
51 int main()
52 {
53     int m, a, b, c;
54     while(~scanf("%d%d", &m, &n))
55     {
56         _clr(flow, 0);
57         while(m--)
58         {
59             scanf("%d%d%d", &a, &b, &c);
60             flow[a][b] += c;
61         }
62         while(!Q.empty()) Q.pop();
63         Push_Relabel();
64     }
65     return 0;
66 }
View Code
原文地址:https://www.cnblogs.com/khan724/p/4289485.html