P3376 【模板】网络最大流
Edmonds−Karp增广路算法
#include <bits/stdc++.h>
using namespace std;
inline int read(int& x) {
char ch = getchar();
int f = 1; x = 0;
while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
return x * f;
}
//void ReadFile() {
// FILE* stream1;
// freopen_s(&stream1,"in.txt", "r", stdin);
// freopen_s(&stream1,"out.txt", "w", stdout);
//}
static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();
#define HEAD(input) cf.head[input]
#define NEXT(input) cf.tail[input].nx
#define VALUE(input) cf.tail[input].v
#define TO(input) cf.tail[input].to
class ChainForward {
struct ChainForwardNode {
ChainForwardNode() :to(0), nx(0), v(0) {}
int to,nx;
long long v;
};
public:
ChainForward(int headLen, int edgeLen) {
init(headLen, edgeLen);
}
void init(int headLen, int edgeLen) {
head.assign(headLen, 0);
tail.assign(edgeLen, {});
tot = 1;
}
int add(int from,int to,int val) {
tail[++tot].to = to;
tail[tot].v = val;
tail[tot].nx = head[from];
head[from] = tot;
return tot;
}
int tot;
vector<int> head;
vector<ChainForwardNode> tail;
};
ChainForward cf(1000,10000);
const int maxn = 207,maxm = 1e4 + 7,INF = 1e9 + 7;
long long n, m, s, t,id[maxn][maxn],pre[maxm],vis[maxn],dis[maxn],ans = 0;
//找增广路
bool bfs() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(s);
vis[s] = 1;
dis[s] = INF;
while (!q.empty()) {
int from = q.front(); q.pop();
for (int i = HEAD(from); i; i = NEXT(i)) {
if (VALUE(i) <= 0)continue;
int to = TO(i);
if (vis[to])continue;
dis[to] = min(dis[from], VALUE(i));
//记录路径
pre[to] = i;
vis[to] = 1;
if (to == t)return true;
q.push(to);
}
}
return false;
}
void update() {
//增广路流量
int x = t,flow = dis[t];
while (x != s) {
int v = pre[x];
//去掉增广路
VALUE(v) -= flow;
//增加反向边
VALUE(v ^ 1) += flow;
//回退
x = TO(v ^ 1);
}
ans += flow;
}
void slove() {
cin >> n >> m >> s >> t;
int a, b, c;
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
if (id[a][b] == 0) {
int idx = cf.add(a, b, c);
cf.add(b, a, 0);
id[a][b] = idx;
}
else {
int idx = id[a][b];
VALUE(idx) += c;
}
}
while (bfs()) {
update();
}
cout << ans << endl;
}
int main() {
slove();
return 0;
}
Edmonds−Karp增广路算法
class NetFlowBase{
public:
typedef long long T;
struct Edge{
int to,nx;
T flow;
Edge(int _to,T _flow,int _nx):to(_to),flow(_flow),nx(_nx){}
};
void Init(int n){
head.assign(n + 1,-1);
}
int Add(int from,int to,T flow){
int ret = tail.size();
Edge e(to,flow,head[from]);
head[from] = tail.size();
tail.push_back(e);
return ret;
}
int Head(int cur){return head[cur];}
int Next(int cur){return tail[cur].nx;}
T &Value(int cur){return tail[cur].flow;}
int &To(int cur){return tail[cur].to;}
vector<Edge> tail;
vector<int> head;
};
class EK:public NetFlowBase{
public:
static const int INF = 1e9;
EK(int _n,int _s,int _t){
n = _n;
vis.assign(n + 1,0);
dis.assign(n + 1,0);
pre.assign(n + 1,0);
s = _s;
t = _t;
Init(n);
}
bool bfs(){
fill(vis.begin(),vis.end(),0);
queue<int> q;
q.push(s);
vis[s] = 1;
dis[s] = INF;
while (!q.empty()) {
int from = q.front(); q.pop();
for (int i = Head(from); ~i; i = Next(i)) {
if (Value(i) <= 0)continue;
int to = To(i);
if (vis[to])continue;
dis[to] = min(dis[from], Value(i));
//记录路径
pre[to] = i;
vis[to] = 1;
if (to == t)return true;
q.push(to);
}
}
return false;
}
T update(){
//增广路流量
T flow = dis[t],ans = 0;
int x = t;
while (x != s) {
int v = pre[x];
//去掉增广路
Value(v) -= flow;
//增加反向边
Value(v ^ 1) += flow;
//回退
x = To(v ^ 1);
}
ans += flow;
return ans;
}
T GetMaxFlow(){
T ans = 0;
while (bfs()) {
ans += update();
}
return ans;
}
vector<bool> vis;
vector<int> pre;
vector<T> dis;
int s,t,n;
};
const int maxn = 207;
int id[maxn][maxn];
void slove() {
int n,m,s,t;
cin >> n >> m >> s >> t;
int a, b, c;
EK ek(n,s,t);
for (int i = 1; i <= m; i++) {
cin >> a >> b >> c;
if (id[a][b] == 0) {
int idx = ek.Add(a, b, c);
ek.Add(b, a, 0);
id[a][b] = idx;
}
else {
int idx = id[a][b];
ek.Value(idx) += c;
}
}
cout << ek.GetMaxFlow() << endl;
}
int main() {
slove();
return 0;
}
vector写法
class NetFlow {
public:
typedef long long T;
struct Edge {
int to, id;
T flow;
Edge(int _to, T _flow, int _id) :to(_to), flow(_flow),id(_id) {}
};
NetFlow(int _n,int _s,int _t) {
e.assign(_n + 1, {});
}
void Add(int from,int to, T flow) {
int alen = e[from].size();
int blen = e[to].size();
e[from].push_back(Edge(to,flow,blen));
e[to].push_back({from,0,alen });
}
T &Value(Edge& edge) {
return edge.flow;
}
int To(Edge& edge) {
return edge.to;
}
int Pre(Edge& edge) {
return edge.id;
}
vector<vector<Edge> > e;
};
class EK :public NetFlow {
public:
static constexpr T INF = 1e15;
EK(int _n, int _s, int _t):NetFlow(_n,_s,_t) {
s = _s;t = _t;n = _n;
vis.assign(n + 1, false); last.assign(n + 1, 0); pre.assign(n + 1, 0); dis.assign(n + 1, 0);
}
bool bfs() {
fill(vis.begin(), vis.end(), false);
queue<int> q;
q.push(s);
dis[s] = INF; vis[s] = true;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int i = 0; i < e[x].size(); i++) {
Edge& edge = e[x][i];
int cur = To(edge);
if (Value(edge) <= 0 || vis[cur]) continue;
vis[cur] = true;
dis[cur] = min(dis[x], Value(edge));
pre[cur] = i;
last[cur] = x;
if (cur == t) return true;
q.push(cur);
}
}
return false;
}
T update() {
//增广路流量
T flow = dis[t], ans = 0;
int x = t;
while (x != s) {
int a = last[x];
int b = pre[x];
Edge& edge = e[a][b];
//去掉增广路
Value(edge) -= flow;
//增加反向边
Edge& revEdge = e[x][Pre(edge)];
Value(revEdge) += flow;
//回退
x = last[x];
}
ans += flow;
return ans;
}
T GetMaxFlow() {
T ans = 0;
while (bfs()) {
ans += update();
}
return ans;
}
int s, t,n;
vector<bool> vis;
vector<int> pre,last;
vector<T> dis;
};
//dinic
class Dinic :public NetFlow {
public:
static constexpr T INF = 1e15;
Dinic(int _n, int _s, int _t) :NetFlow(_n, _s, _t) {
s = _s; t = _t; n = _n;
dep.assign(n + 1, 0); arc.assign(n + 1, 0);
}
bool bfs() {
queue<int> q;
q.push(s);
fill(dep.begin(), dep.end(), -1);
dep[s] = 0;
while (!q.empty()) {
int from = q.front(); q.pop();
for (auto& edge : e[from]) {
int cur = To(edge);
if (dep[cur] != -1 || Value(edge) <= 0) continue;
dep[cur] = dep[from] + 1;
q.push(cur);
}
}
fill(arc.begin(), arc.end(), 0);
return dep[t] != -1;
}
T dfs(int x, long long sum) {
if (x == t) return sum;
T flow = 0;
for (int i = arc[x]; i < e[x].size(); i++) {
Edge& edge = e[x][i];
arc[x] = i;
int cur = To(edge);
if (Value(edge) > 0 && dep[cur] == dep[x] + 1) {
if (flow = dfs(cur, min(sum, Value(edge)) ) ) {
Value(edge) -= flow;
Edge& PreEdge = e[cur][Pre(edge)];
Value(PreEdge) += flow;
return flow;
}
else dep[cur] = -1;
}
}
return flow;
}
T GetMaxFlow() {
int flow = 0;
T ans = 0;
while (bfs()) {
while (flow = dfs(s, INF))ans += flow;
}
return ans;
}
vector<int> dep,arc;
int s, n, t;
};
//ISAP
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
char ch = getchar();
long long f = 1,x = 0;
while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
return x * f;
}
//void ReadFile() {
// FILE* stream1;
// freopen_s(&stream1,"in.txt", "r", stdin);
// freopen_s(&stream1,"out.txt", "w", stdout);
//}
static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();
#define HEAD(input) cf.head[input]
#define NEXT(input) cf.tail[input].nx
#define VALUE(input) cf.tail[input].v
#define TO(input) cf.tail[input].to
#define ADD(a,b,c) cf.add(a,b,c)
class ChainForward {
struct ChainForwardNode {
ChainForwardNode() :to(0), nx(0), v(0) {}
int to,nx;
long long v;
};
public:
ChainForward(int headLen, int edgeLen) {
init(headLen, edgeLen);
}
void init(int headLen, int edgeLen) {
head.assign(headLen, 0);
tail.assign(edgeLen, {});
tot = 1;
}
int add(int from,int to,long long val) {
tail[++tot].to = to;
tail[tot].v = val;
tail[tot].nx = head[from];
head[from] = tot;
return tot;
}
int tot;
vector<int> head;
vector<ChainForwardNode> tail;
};
ChainForward cf(2000, 5e5 + 7);
const int maxn = 2e3;
const long long INF = 1e15 + 7;
int dep[maxn], gap[maxn],id[maxn][maxn];
long long n, m, s, t,ans = 0;
void bfs() {
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
queue<int> q;
q.push(t);
dep[t] = 0;
gap[0] = 1;
while (!q.empty()) {
int from = q.front();
q.pop();
for (int i = HEAD(from); i; i = NEXT(i)) {
int to = TO(i);
if (dep[to] == -1) {
dep[to] = dep[from] + 1;
gap[dep[to]]++;
q.push(to);
}
}
}
return;
}
long long dfs(int x, long long flow) {
if (x == t) return flow;
long long used = 0;
for (int i = HEAD(x); i; i = NEXT(i)) {
int to = TO(i);
if (VALUE(i) && dep[to] + 1 == dep[x]) {
long long ret = dfs(to, min(flow - used, VALUE(i)));
if (ret) {
VALUE(i) -= ret;
VALUE(i ^ 1) += ret;
used += ret;
}
if (used == flow) return used;
}
}
--gap[dep[x]];
if (gap[dep[x]] == 0) {
dep[s] = n + 1;
}
dep[x]++;
gap[dep[x]]++;
return used;
}
void ISAP() {
ans = 0;
bfs();
while (dep[s] < n) {
ans += dfs(s, INF);
}
printf("%lld\n", ans);
//cout << ans << endl;
}
signed main() {
n = read(), m = read(), s = read(), t = read();
//cin >> n >> m >> s >> t;
for (int i = 1; i <= m; i++) {
int a, b, c;
//cin >> a >> b >> c;
a = read(), b = read(), c = read();
if (id[a][b] == 0) {
id[a][b] = ADD(a, b, c);
ADD(b, a, 0);
}
else {
VALUE(id[a][b]) += c;
}
}
ISAP();
return 0;
}
HLPP
#include <bits/stdc++.h>
using namespace std;
inline long long read() {
char ch = getchar();
long long f = 1,x = 0;
while (ch > '9' || ch < '0') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + ch - '0'; ch = getchar(); }
return x * f;
}
//void ReadFile() {
// FILE* stream1;
// freopen_s(&stream1,"in.txt", "r", stdin);
// freopen_s(&stream1,"out.txt", "w", stdout);
//}
static auto speedup = []() {ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); return nullptr; }();
const int N = 2000, M = 150000, INF = 0x3f3f3f3f;
int n, m, s, t;
struct qxx {
int nex, t;
long long v;
};
qxx e[M * 2 + 1];
int h[N + 1], cnt = 1;
void add_path(int f, int t, long long v) {
e[++cnt] = qxx{ h[f], t, v }, h[f] = cnt;
}
void add_flow(int f, int t, long long v) {
add_path(f, t, v);
add_path(t, f, 0);
}
int ht[N + 1]; // 高度;
long long ex[N + 1]; // 超额流;
int gap[N]; // gap 优化. gap[i] 为高度为 i 的节点的数量
stack<int> B[N]; // 桶 B[i] 中记录所有 ht[v]==i 的v
int level = 0; // 溢出节点的最高高度
int push(int u) { // 尽可能通过能够推送的边推送超额流
bool init = u == s; // 是否在初始化
for (int i = h[u]; i; i = e[i].nex) {
const int& v = e[i].t;
const long long& w = e[i].v;
// 初始化时不考虑高度差为1
if (!w || (init == false && ht[u] != ht[v] + 1) || ht[v] == INF) continue;
long long k = init ? w : min(w, ex[u]);
// 取到剩余容量和超额流的最小值,初始化时可以使源的溢出量为负数。
if (v != s && v != t && !ex[v]) B[ht[v]].push(v), level = max(level, ht[v]);
ex[u] -= k, ex[v] += k, e[i].v -= k, e[i ^ 1].v += k; // push
if (!ex[u]) return 0; // 如果已经推送完就返回
}
return 1;
}
void relabel(int u) { // 重贴标签(高度)
ht[u] = INF;
for (int i = h[u]; i; i = e[i].nex)
if (e[i].v) ht[u] = min(ht[u], ht[e[i].t]);
if (++ht[u] < n) { // 只处理高度小于 n 的节点
B[ht[u]].push(u);
level = max(level, ht[u]);
++gap[ht[u]]; // 新的高度,更新 gap
}
}
bool bfs_init() {
memset(ht, 0x3f, sizeof(ht));
queue<int> q;
q.push(t), ht[t] = 0;
while (q.size()) { // 反向 BFS, 遇到没有访问过的结点就入队
int u = q.front();
q.pop();
for (int i = h[u]; i; i = e[i].nex) {
const int& v = e[i].t;
if (e[i ^ 1].v && ht[v] > ht[u] + 1) ht[v] = ht[u] + 1, q.push(v);
}
}
return ht[s] != INF; // 如果图不连通,返回 0
}
// 选出当前高度最大的节点之一, 如果已经没有溢出节点返回 0
int select() {
while (B[level].size() == 0 && level > -1) level--;
return level == -1 ? 0 : B[level].top();
}
long long hlpp() { // 返回最大流
if (!bfs_init()) return 0; // 图不连通
memset(gap, 0, sizeof(gap));
for (int i = 1; i <= n; i++)
if (ht[i] != INF) gap[ht[i]]++; // 初始化 gap
ht[s] = n;
push(s); // 初始化预流
int u;
while ((u = select())) {
B[level].pop();
if (push(u)) { // 仍然溢出
if (!--gap[ht[u]])
for (int i = 1; i <= n; i++)
if (i != s && ht[i] > ht[u] && ht[i] < n + 1)
ht[i] = n + 1; // 这里重贴成 n+1 的节点都不是溢出节点
relabel(u);
}
}
return ex[t];
}
int main() {
scanf_s("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1, u, v, w; i <= m; i++) {
scanf_s("%d%d%d", &u, &v, &w);
add_flow(u, v, w);
}
printf("%lld", hlpp());
return 0;
}