最大流
1. EK算法
这个算法效率谈不上多高,写上来主要是防止出现什么必须得用它的情况
//P3376
#include <bits/stdc++.h>
using namespace std;
struct Edge {
int from, to, flow;
Edge(int u, int v, int f) : from(u), to(v), flow(f) {}
};
const int N = 210;
int n, m, s, t;
vector<Edge> edges;
vector<int> G[N];
int vis[N], inch[N], pre[N];
long long maxflow;
void addEdge(int from, int to, int flow) {
edges.push_back((Edge){from, to, flow});
G[from].push_back(edges.size() - 1);
}
bool bfs() {
memset(vis, 0, sizeof(vis));
queue<int> q;
q.push(s), vis[s] = 1, inch[s] = 0x3f3f3f3f;
while (!q.empty()) {
int x = q.front(); q.pop();
if (x == t) return true;
for (int i = 0; i < G[x].size(); ++i) {
Edge &e = edges[G[x][i]];
int to = e.to;
if (vis[to] || e.flow == 0)
continue;
inch[to] = min(inch[x], e.flow);
pre[to] = G[x][i];
q.push(to), vis[to] = 1;
}
}
return false;
}
void update() {
int x = t;
while (x != s) {
int i = pre[x];
edges[ i ].flow -= inch[t];
edges[i^1].flow += inch[t];
x = edges[i].from;
}
maxflow += inch[t];
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1; i <= m; ++i) {
int from, to, flow;
scanf("%d%d%d", &from, &to, &flow);
addEdge(from, to, flow);
addEdge(to, from, 0);
}
while (bfs()) update();
printf("%lld\n", maxflow);
return 0;
}
2. Dinic 算法
基于EK算法的优化,效率很高,基本上不太可能被卡。
#include<bits/stdc++.h>
using namespace std;
const int N = 210, M = 5010 * 2, INF = 1 << 30;
int n, m, s, t;
//
int tot, head[N], Next[M], ver[M], Flow[M];
void addEdge(int u, int v, int f) {
ver[++tot] = v, Flow[tot] = f;
Next[tot] = head[u], head[u] = tot;
}
//
int d[N];
queue<int> q;
bool bfs()
{
memset(d, 0, sizeof(d));
while (!q.empty()) q.pop();
q.push(s), d[s] = 1;
while (!q.empty()) {
int x = q.front(); q.pop();
if (x == t) return true;
for (int i = head[x]; i; i = Next[i]) {
int to = ver[i];
if (!d[to] && Flow[i])
q.push(to), d[to] = d[x] + 1;
}
}
return false;
}
//
int Dinic(int x, int flow) {
if (x == t) return flow;
int rest = flow;
for (int i = head[x]; i; i = Next[i]) {
int to = ver[i];
if (Flow[i] && d[to] == d[x] + 1) {
int k = Dinic(to, min(rest, Flow[i]));
if (!k) d[to] = 0;
Flow[i] -= k, Flow[i^1] += k;
rest -= k;
if (rest == 0) break;
}
}
if (rest == flow) d[x] = 0;
return flow - rest;
}
int main()
{
//input
scanf("%d%d%d%d", &n, &m, &s, &t);
tot = -1;
for (int i = 1; i <= m; ++i) {
int from, to, flow;
scanf("%d%d%d", &from, &to, &flow);
addEdge(from, to, flow);
addEdge(to, from, 0 );
}
//solve
long long maxflow = 0;
int flow;
while (bfs())
while (flow = Dinic(s, INF)) maxflow += flow;
//output
printf("%lld\n", maxflow);
return 0;
}
费用流
最小费用最大流
和 EK 算法类似,不过把增广路的 BFS 换成了 SPFA
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 5010, M = 100010;
const LL INF = 0x3f3f3f3f3f3f3f3f;
int n, m, s, t;
LL maxflow, ans;
int tot, Head[N], Next[M], ver[M];
LL Flow[M], Cost[M];
void addEdge(int u, int v, LL flow, LL cost) {
ver[++tot] = v, Flow[tot] = flow, Cost[tot] = cost;
Next[tot] = Head[u], Head[u] = tot;
}
LL d[N], incf[N];
int pre[N], vis[N];
bool SPFA() {
queue<int> q;
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
q.push(s), d[s] = 0, vis[s] = 1;
incf[s] = INF;
while (!q.empty()) {
int x = q.front(); q.pop();
vis[x] = 0;
for (int i = Head[x]; i; i = Next[i]) {
if (!Flow[i]) continue;
int to = ver[i];
if (d[to] > d[x] + Cost[i]) {
d[to] = d[x] + Cost[i];
incf[to] = min(incf[x], Flow[i]);
pre[to] = i;
if (!vis[to]) vis[to] = 1, q.push(to);
}
}
}
return (d[t] != INF);
}
void update() {
int x = t;
while (x != s) {
int i = pre[x];
Flow[i] -= incf[t], Flow[i^1] += incf[t];
x = ver[i^1];
}
maxflow += incf[t];
ans += d[t] * incf[t];
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &t);
tot = 1;
for (int i = 1; i <= m; ++i) {
int u, v;
LL flow, cost;
scanf("%d%d%lld%lld", &u, &v, &flow, &cost);
addEdge(u, v, flow, cost);
addEdge(v, u, 0 , -cost);
}
while (SPFA()) update();
printf("%lld %lld", maxflow, ans);
return 0;
}
最大费用最大流
将费用取反后放进图里跑,得到的结果的相反数就是答案。