最大流模板

  1 /*

  2  *最大流模板(引用学长的模板。。。)

  3  * SAP(当前弧优化+GAP优化)非递归形式  7  */

  8 

  9 #include <cstring>

 10 #include <iostream>

 11 #include <cstdio>

 12 

 13 #define SETZR(a) memset(a,0,sizeof(a))

 14 

 15 using namespace std;

 16 

 17 //定义常量:边数、点数和无穷

 18 const int MAXM = 1000000;

 19 const int MAXN = 10000;

 20 const int INF = 1000000000;

 21 

 22 //边的结构体

 23 //此模板中图以池子法存储

 24 

 25 struct record {

 26     int v, f, next;

 27 } edge[MAXM];

 28 

 29 /*

 30  * 变量说明:

 31  * pointer为各点出度头指针

 32  * dis为距离标号

 33  * vh记录每个距离标号点的数量,用于GAP优化

 34  * his记录各点入栈时的流量,用于退栈

 35  * di记录各点当前弧

 36  * pre记录各点前驱结点,同样用于退栈

 37  */

 38 int n, m, s, t, cas, cl;

 39 int pointer[MAXN], dis[MAXN], vh[MAXN];

 40 int his[MAXN], di[MAXN], pre[MAXN];

 41 

 42 void connect(int a, int b, int f) {

 43     cl++;

 44     edge[cl].next = pointer[a];

 45     edge[cl].v = b;

 46     edge[cl].f = f;

 47     pointer[a] = cl;

 48     cl++;

 49     edge[cl].next = pointer[b];

 50     edge[cl].v = a;

 51     edge[cl].f = 0; //若为无向边,则f = f

 52     pointer[b] = cl;

 53 }

 54 

 55 int main() {

 56     scanf("%d", &cas);

 57     while (cas--) {

 58         scanf("%d%d%d%d", &n, &m, &s, &t);

 59         //初始化

 60         cl = 1;

 61         SETZR(dis);

 62         SETZR(vh);

 63         SETZR(pointer);

 64         //建图

 65         for (int i = 0; i < m; i++) {

 66             int p, k, w;

 67             scanf("%d%d%d", &p, &k, &w);

 68             connect(p, k, w);

 69         }

 70         //最大流过程

 71         vh[0] = n; //初始化GAP数组(默认所有点的距离标号均为0,则距离标号为0的点数量为n)

 72         for (int i = 0; i < n; i++) di[i] = pointer[i]; //初始化当前弧

 73         int i = s, aug = INF, flow = 0; //初始化一些变量,flow为全局流量,aug为当前增广路的流量

 74         bool flag = 0; //标记变量,记录是否找到了一条增广路(若没有找到则修正距离标号)

 75         while (dis[s] < n) {

 76             his[i] = aug; //保存当前流量

 77             flag = 0;

 78             int p = di[i];

 79             while (p != 0) {

 80                 if ((edge[p].f > 0) && (dis[edge[p].v] + 1 == dis[i])) {//利用距离标号判定可行弧

 81                     flag = 1; //发现可行弧

 82                     di[i] = p; //更新当前弧

 83                     aug = min(aug, edge[p].f); //更新当前流量

 84                     pre[edge[p].v] = p; //记录前驱结点

 85                     i = edge[p].v; //在弧上向前滑动

 86                     if (i == t) {//遇到汇点,发现可增广路

 87                         flow += aug; //更新全局流量

 88                         while (i != s) {//减少增广路上相应弧的容量,并增加其反向边容量

 89                             edge[pre[i]].f -= aug;

 90                             edge[pre[i]^1].f += aug;

 91                             i = edge[pre[i]^1].v;

 92                         }

 93                         aug = INF;

 94                     }

 95                     break;

 96                 }

 97                 p = edge[p].next;

 98             }

 99             if (flag) continue; //若发现可行弧则继续,否则更新标号

100             int min = n - 1;

101             p = pointer[i];

102             while (p != 0) {

103                 if ((edge[p].f > 0) && (dis[edge[p].v] < min)) {

104                     di[i] = p; //不要忘了重置当前弧

105                     min = dis[edge[p].v];

106                 }

107                 p = edge[p].next;

108             }

109             --vh[dis[i]];

110             if (vh[dis[i]] == 0) break; //更新vh数组,若发现距离断层,则算法结束(GAP优化)

111             dis[i] = min + 1;

112             ++vh[dis[i]];

113             if (i != s) {//退栈过程

114                 i = edge[pre[i]^1].v;

115                 aug = his[i];

116             }

117         }

118         //输出答案

119         printf("%d\n", flow);

120     }

121     return 0;

122 }

你可能感兴趣的:(最大流)