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 }