[Flows] 网络流做题记录
Some Templates
Maximum Flow (Minimum Cut)
template < class T, int N, int M >
struct MaxFlow {
int n;
int cnt = 1, head[N];
struct Edge {
T flow;
int nxt, node;
} e[M << 1];
int dep[N], cur[N], flow_sink;
void add_edge_ (int u, int v, T flow) {
cnt ++;
e[cnt].nxt = head[u];
e[cnt].node = v;
e[cnt].flow = flow;
head[u] = cnt;
return ;
}
void add_edge (int u, int v, T flow) {
add_edge_ (u, v, flow);
add_edge_ (v, u, 0);
return ;
}
T dfs (int u, T remain) {
if (u == flow_sink) {
return remain;
}
T res = 0;
for (int i = cur[u]; i && remain; i = e[i].nxt) {
cur[u] = i;
T f = std :: min (remain, e[i].flow);
int v = e[i].node;
if (dep[u] + 1 == dep[v] && f) {
T f_ = dfs (v, f);
res += f_;
remain -= f_;
e[i].flow -= f_;
e[i ^ 1].flow += f_;
}
}
if (!res) {
dep[u] = -1;
}
return res;
}
T Flow (int source, int sink) {
flow_sink = sink;
T res = 0;
while (true) {
std :: queue < int > q;
while (!q.empty ()) {
q.pop ();
}
for (int i = 0;i <= n; ++ i) {
cur[i] = head[i];
dep[i] = -1;
}
q.push (source);
dep[source] = 0;
while (!q.empty ()) {
int u = q.front ();
q.pop ();
for (int i = head[u]; i ; i = e[i].nxt) {
if (dep[e[i].node] == -1 && e[i].flow) {
dep[e[i].node] = dep[u] + 1;
q.push (e[i].node);
}
}
}
if (dep[sink] == -1) {
return res;
}
res += dfs (source, 1e18);
}
return 0;
}
void init (int n_) {
n = n_;
cnt = 1;
for (int i = 1;i <= n; ++ i) {
head[i] = 0;
}
return ;
}
};
Minimum Cost Maximum Flow
template < class T, int N, int M, i64 INF >
struct MinCost_MaxFlow {
struct Edge {
int node, nxt;
T flow, cost;
} e[M << 1];
struct Node {
int node, id;
} p[M];
int n;
int cnt = 1, head[N];
int vis[N], flow_source, flow_sink;
T MaxFlow, MinCost, dis[N], h[N];
void add_edge_ (int u, int v, T flow, T cost) {
cnt ++;
e[cnt].node = v;
e[cnt].flow = flow;
e[cnt].cost = cost;
e[cnt].nxt = head[u];
head[u] = cnt;
return ;
}
bool dijkstra () {
std :: priority_queue < std :: pair < T, int >,
std :: vector < std :: pair < T, int > >,
std :: greater < std :: pair < T, int > > > q;
while (!q.empty ()) {
q.pop ();
}
for (int i = 1;i <= n; ++ i) {
dis[i] = (T) (INF);
vis[i] = 0;
}
dis[flow_source] = 0;
q.push (std :: make_pair (0, flow_source));
while (!q.empty ()) {
int u = q.top ().second;
q.pop ();
if (vis[u]) {
continue;
}
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].node;
T w = e[i].cost + h[u] - h[v];
if (e[i].flow != 0 && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
p[v].node = u;
p[v].id = i;
if (!vis[v]) {
q.push (std :: make_pair (dis[v], v));
}
}
}
}
if (dis[flow_sink] != (T) (INF)) return true;
else return false;
}
void SPFA () {
std :: queue < int > q;
while (!q.empty ()) {
q.pop ();
}
std :: memset (h, 63, sizeof h);
h[flow_source] = 0;
vis[flow_source] = 1;
q.push (flow_source);
while (!q.empty ()) {
int u = q.front ();
q.pop ();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].node;
if (e[i].flow != 0 && h[v] > h[u] + e[i].cost) {
h[v] = h[u] + e[i].cost;
if (!vis[v]) {
vis[v] = 1;
q.push (v);
}
}
}
}
return ;
}
void add_edge (int u, int v, T flow, T cost) {
add_edge_ (u, v, flow, cost);
add_edge_ (v, u, 0, -cost);
return ;
}
std :: pair < T, T > Flow (int source, int sink) {
flow_source = source;
flow_sink = sink;
SPFA ();
MaxFlow = 0;
MinCost = 0;
while (dijkstra ()) {
T w = INF;
for (int i = 1;i <= n; ++ i) {
h[i] += dis[i];
}
for (int i = sink; i != source; i = p[i].node) {
w = std :: min (w, e[p[i].id].flow);
}
for (int i = sink; i != source; i = p[i].node) {
e[p[i].id].flow -= w;
e[p[i].id ^ 1].flow += w;
}
MaxFlow += w;
MinCost += w * h[sink];
}
return std :: make_pair (MaxFlow, MinCost);
}
void init (int n_) {
n = n_;
cnt = 1;
MaxFlow = 0;
MinCost = 0;
for (int i = 1;i <= n; ++ i) {
head[i] = h[i] = vis[i] = dis[i] = 0;
}
flow_source = 0;
flow_sink = 0;
return ;
}
};
洛谷 P2045 方格取数加强版
考虑拆点,将
考虑用 流 表示这个点的 经过次数,用 费用 表示 所经过的数的和。
-
第一次经过
,获利 ,从 向 连一条 容量为 ,费用为 的边。 -
以前已经经过过
,获利 ,从 向 连一条 容量为 ,费用为 的边。 -
从
向右走到 ,获利 ,从 向 连一条 容量为 ,费用为 的边。 -
从
向下走到 ,获利 ,从 向 连一条 容量为 ,费用为 的边。
最终的 源点设为
最后跑一遍最大费用最大流即可,可以将费用取反跑最小费用最大流。
Code
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/rope>
bool Mbe;
typedef long long i64;
typedef unsigned long long u64;
typedef __int128 i128;
std :: mt19937 rnd (std :: time (0));
template < class T > T gen (const T l, const T r) {return rnd () % (r - l + 1) + l;}
const double pi = std :: acos (-1);
template < class T > inline void read (T &val) {
T x = 0;
bool f = false;
char c = std :: getchar ();
for ( ; c < '0' || c > '9' ; c = std :: getchar ()) f |= (c == '-');
for ( ; c >= '0' && c <= '9' ; c = std :: getchar ()) x = (x << 1) + (x << 3) + (c & 15);
val = (!f) ? (x) : (-x);
return ;
}
#define debug(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
const i64 hashmod1 = 2147483579, hashmod2 = 1610612741, hashmod3 = 805306457;
template < class T, class I > void chkmin (T &p, I q) {T q_ = q; p = std :: min (p, q_); return ;}
template < class T, class I > void chkmax (T &p, I q) {T q_ = q; p = std :: max (p, q_); return ;}
template < class T, int N, int M, i64 INF >
struct MinCost_MaxFlow {
struct Edge {
int node, nxt;
T flow, cost;
} e[M << 1];
struct Node {
int node, id;
} p[M];
int n;
int cnt = 1, head[N];
int vis[N], flow_source, flow_sink;
T MaxFlow, MinCost, dis[N], h[N];
void add_edge_ (int u, int v, T flow, T cost) {
cnt ++;
e[cnt].node = v;
e[cnt].flow = flow;
e[cnt].cost = cost;
e[cnt].nxt = head[u];
head[u] = cnt;
return ;
}
bool dijkstra () {
std :: priority_queue < std :: pair < T, int >,
std :: vector < std :: pair < T, int > >,
std :: greater < std :: pair < T, int > > > q;
while (!q.empty ()) {
q.pop ();
}
for (int i = 1;i <= n; ++ i) {
dis[i] = (T) (INF);
vis[i] = 0;
}
dis[flow_source] = 0;
q.push (std :: make_pair (0, flow_source));
while (!q.empty ()) {
int u = q.top ().second;
q.pop ();
if (vis[u]) {
continue;
}
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].node;
T w = e[i].cost + h[u] - h[v];
if (e[i].flow != 0 && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
p[v].node = u;
p[v].id = i;
if (!vis[v]) {
q.push (std :: make_pair (dis[v], v));
}
}
}
}
if (dis[flow_sink] != (T) (INF)) return true;
else return false;
}
void SPFA () {
std :: queue < int > q;
while (!q.empty ()) {
q.pop ();
}
std :: memset (h, 63, sizeof h);
h[flow_source] = 0;
vis[flow_source] = 1;
q.push (flow_source);
while (!q.empty ()) {
int u = q.front ();
q.pop ();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].node;
if (e[i].flow != 0 && h[v] > h[u] + e[i].cost) {
h[v] = h[u] + e[i].cost;
if (!vis[v]) {
vis[v] = 1;
q.push (v);
}
}
}
}
return ;
}
void add_edge (int u, int v, T flow, T cost) {
add_edge_ (u, v, flow, cost);
add_edge_ (v, u, 0, -cost);
return ;
}
std :: pair < T, T > Flow (int source, int sink) {
flow_source = source;
flow_sink = sink;
SPFA ();
MaxFlow = 0;
MinCost = 0;
while (dijkstra ()) {
T w = INF;
for (int i = 1;i <= n; ++ i) {
h[i] += dis[i];
}
for (int i = sink; i != source; i = p[i].node) {
w = std :: min (w, e[p[i].id].flow);
}
for (int i = sink; i != source; i = p[i].node) {
e[p[i].id].flow -= w;
e[p[i].id ^ 1].flow += w;
}
MaxFlow += w;
MinCost += w * h[sink];
}
return std :: make_pair (MaxFlow, MinCost);
}
void init (int n_) {
n = n_;
cnt = 1;
MaxFlow = 0;
MinCost = 0;
for (int i = 1;i <= n; ++ i) {
head[i] = h[i] = vis[i] = dis[i] = 0;
}
flow_source = 0;
flow_sink = 0;
return ;
}
};
int n, k;
i64 a[65][65];
MinCost_MaxFlow < i64, 5027, 10026, (i64) (1e18) > g;
bool Med;
signed main () {
debug ("%.8lf MB\n", (&Mbe - &Med) / 1048576.0);
read (n), read (k);
for (int i = 1;i <= n; ++ i) {
for (int j = 1;j <= n; ++ j) {
read (a[i][j]);
}
}
g.init (2 * n * n + 1);
#define id_IN(x, y) (x - 1) * n + y + 1
#define id_OUT(x, y) n * n + (x - 1) * n + y + 1
for (int i = 1;i <= n; ++ i) {
for (int j = 1;j <= n; ++ j) {
g.add_edge (id_IN (i, j), id_OUT (i, j), 1, -a[i][j]);
g.add_edge (id_IN (i, j), id_OUT (i, j), 1e18, 0);
if (i != n) g.add_edge (id_OUT (i, j), id_IN (i + 1, j), 1e18, 0);
if (j != n) g.add_edge (id_OUT (i, j), id_IN (i, j + 1), 1e18, 0);
}
}
g.add_edge (1, id_IN (1, 1), k, 0);
auto ans = g.Flow (1, id_OUT (n, n));
printf ("%lld\n", -ans.second);
#undef id_IN
#undef id_OUT
debug ("%.8lf ms\n", 1e3 * clock () / CLOCKS_PER_SEC);
return 0;
}
// g++ "a.cpp" -o a -std=c++14 -O2 -Wall -Wextra -Wshadow
// check! no inline! (except fastIO)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下