题意:给出m条路,n个点,每条路给出u,v,cap,求1~n的最大flow
题解:直接上ISAP,其实Dinic也可以.
这里使用的是最大流-ISAP模板(ISAP + 当前弧优化 + GAP优化)
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = (int)1e5 + 500;
struct Edge {
int v;//弧尾
int cap;
int n;//指向下一条从同一个弧头出发的弧
} edge[maxn];
int adj[maxn];//前向星的表头
int Q[maxn], head, tail;//队列
int d[maxn], cur[maxn], pre[maxn], num[maxn];
int nv;//编号修改的上限
int top;
void add(int u, int v, int cap) {
//正向边
edge[top].v = v;
edge[top].cap = cap;
edge[top].n = adj[u];
adj[u] = top++;
//反向边
edge[top].v = u;
edge[top].cap = 0;
edge[top].n = adj[v];
adj[v] = top++;
}
void rev_bfs(int t) {//反向BFS标号
memset(num, 0, sizeof(num));
memset(d, -1, sizeof(d));//没标过号则为-1
d[t] = 0;//汇点默认为标过号
num[0] = 1;
head = tail = 0;
Q[tail++] = t;
while (head != tail) {
int u = Q[head++];
for (int i = adj[u]; ~i; i = edge[i].n) {
int v = edge[i].v;
if (~d[v]) continue;//已经标过号
d[v] = d[u] + 1;//标号
Q[tail++] = v;
num[d[v]]++;
}
}
}
int max_flow(int s, int t) {
memcpy(cur, adj, sizeof(cur));//复制,当前弧优化
rev_bfs(t);//只用标号一次就够了,重标号在ISAP主函数中进行就行了
int flow = 0, u = pre[s] = s;
while (d[t] < nv) {//最长也就是一条链,其中最大的标号只会是nv - 1,
//如果大于等于nv了说明中间已经断层了。
if (u == t) { //如果已经找到了一条增广路,则沿着增广路修改流量
int f = inf, neck;
for (int i = s; i != t; i = edge[cur[i]].v) {
if (f > edge[cur[i]].cap) {
f = edge[cur[i]].cap;//不断更新需要减少的流量
neck = i;//记录回退点,目的是为了不用再回到起点重新找
}
}
for (int i = s; i != t; i = edge[cur[i]].v) { //修改流量
edge[cur[i]].cap -= f;
edge[cur[i] ^ 1].cap += f;
}
flow += f;//更新
u = neck;//回退
}
int i;
for (i = cur[u]; ~i; i = edge[i].n)
if (d[edge[i].v] + 1 == d[u] && edge[i].cap)
break;
if (~i) {//如果存在可行增广路,更新
cur[u] = i;//修改当前弧
pre[edge[i].v] = u;
u = edge[i].v;
}
else { //否则回退,重新找增广路
if (0 == (--num[d[u]])) //GAP间隙优化,如果出现断层,可以知道
//一定不会再有增广路了
break;
int mind = nv;
for (i = adj[u]; ~i; i = edge[i].n) {
if (edge[i].cap && mind > d[edge[i].v]) {//寻找可以增广的最小标号
cur[u] = i;//修改当前弧
mind = d[edge[i].v];
}
}
d[u] = mind + 1;
num[d[u]]++;
u = pre[u];//回退
}
}
return flow;
}
void init() {
memset(adj, -1, sizeof(adj));
top = 0;
}
int main() {
int m, n;
while (~scanf("%d%d", &m, &n)) {
init();
int u, v, w;
for (int i = 0; i < m; ++i) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
nv = n + 1;
printf("%d\n", max_flow(1, n));//这个是从1到n的
}
return 0;
}