EK.

很少用到,知道思想即可。

懒得写封装的屑。

queue<int> q;
int Cap[MAXN][MAXN], Flow[MAXN][MAXN], Aug[MAXN], fa[MAXN], n;
void Add_Cap(int u, int v, int C) { Cap[u][v] += C; } int bfs(int s, int t) {
for(int i = 1; i <= n; i++) {
Aug[i] = 0;
fa[i] = 0;
}
while(!q.empty())
q.pop();
Aug[s] = INF;
q.push(s);
while(!q.empty()) {
int u = q.front();
q.pop();
for(int v = 1; v <= n; v++)
if(Cap[u][v] - Flow[u][v] > 0 && !Aug[v]) {
Aug[v] = Min(Aug[u], Cap[u][v] - Flow[u][v]);
fa[v] = u;
if(v == t)
return Aug[v];
q.push(v);
}
}
return 0;
} int EK(int s, int t) {
int Delta = bfs(s, t), res = 0, u;
while(Delta) {
res += Delta;
for(int v = t; v != s; v = u) {
u = fa[v];
Flow[u][v] += Delta;
Flow[v][u] -= Delta;
}
Delta = bfs(s, t);
}
return res;
}

Dinic.

时间复杂度玄学的常用最大流板子。

struct Maximum_Flow {
#define Type int
struct edge {
int v, nxt;
edge() {}
edge(int V, int Nxt) {
v = V, nxt = Nxt;
}
} e[MAXM << 1];
int n, cnt, s, t;
Type Cap[MAXM << 1], Flow[MAXM << 1];
int Lab[MAXL], Cur[MAXL], head[MAXL], Col[MAXL];
queue<int> q; void init(int N, int S, int T) {
for(int i = 0; i <= cnt; i++)
Flow[i] = 0, Cap[i] = 0;
n = N, cnt = 0, s = S, t = T;
for(int i = 1; i <= n; i++)
head[i] = -1, Col[i] = 0;
} void Add_Edge(int u, int v, Type w) {
Cap[cnt] += w;
e[cnt] = edge(v, head[u]);
head[u] = cnt++;
e[cnt] = edge(u, head[v]);
head[v] = cnt++;
} bool Lab_Vertex() {
for(int i = 1; i <= n; i++)
Lab[i] = 0;
Lab[t] = 1;
while(!q.empty())
q.pop();
q.push(t);
while(!q.empty()) {
int v = q.front();
q.pop();
for(int i = head[v], u; ~i; i = e[i].nxt) {
u = e[i].v;
if(!Lab[u] && Cap[i ^ 1] - Flow[i ^ 1]) {
Lab[u] = Lab[v] + 1;
q.push(u);
if(u == s)
return Lab[s];
}
}
}
return Lab[s];
} Type Widen(int u, Type Limit) {
if(u == t)
return Limit;
Type Used = 0, Delta;
for(int i = Cur[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
Cur[u] = i;
if(Lab[v] + 1 != Lab[u] || Cap[i] - Flow[i] <= 0)
continue;
Delta = Widen(v, Min(Limit - Used, Cap[i] - Flow[i]));
Used += Delta, Flow[i] += Delta, Flow[i ^ 1] -= Delta;
if(Used == Limit)
return Used;
}
return Used;
} Type Dinic() {
Type res = 0;
while(Lab_Vertex()) {
for(int i = 1; i <= n; i++)
Cur[i] = head[i];
res += Widen(s, INF);
if(res < 0)
return INF;
}
return res;
} void Color(int u) {
Col[u] = 1;
for(int i = head[u]; ~i; i = e[i].nxt)
if(Cap[i] - Flow[i] > 0 && !Col[e[i].v])
Color(e[i].v);
} #undef Type
} Flow_Graph;

spfa + Dinic.

普通最小费用最大流。(小心被卡?

struct Minimum_Cost_Maximum_Flow {
#define Type int
struct edge {
int v, nxt;
Type Wei, Cap, Flow;
edge() {}
edge(int V, int Nxt, Type C, Type W, Type F) {
v = V, nxt = Nxt, Cap = C, Wei = W, Flow = F;
}
} e[MAXM << 1];
int head[MAXM << 1], cnt = 0;
void Add_Edge(int u, int v, Type c, Type w) {
e[cnt] = edge(v, head[u], c, w, 0);
head[u] = cnt++;
e[cnt] = edge(u, head[v], 0, -w, 0);
head[v] = cnt++;
} int Cur[MAXN], n, s, t;
bool vis[MAXN], Flag[MAXN];
Type Dist[MAXN], Aug[MAXN], Flow, Cost; void init(int N, int S, int T) {
n = N, s = S, t = T, cnt = 0;
for(int i = 1; i <= n; i++)
head[i] = -1;
} bool spfa() {
for(int i = 1; i <= n; i++)
Dist[i] = INF, vis[i] = false, Aug[i] = INF;
Dist[s] = 0, vis[s] = true, Aug[s] = INF;
queue<int> q;
q.push(s);
while(!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for(int i = head[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
if(e[i].Cap - e[i].Flow > 0 && Dist[v] > Dist[u] + e[i].Wei) {
Dist[v] = Dist[u] + e[i].Wei;
Aug[v] = Min(Aug[u], e[i].Cap - e[i].Flow);
if(!vis[v])
vis[v] = true, q.push(v);
}
}
}
return Dist[t] != INF;
} Type Widen(int u, Type Limit) {
if(u == t)
return Limit;
Flag[u] = true;
Type Used = 0, Delta;
for(int i = Cur[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
if(Flag[v] || Dist[u] + e[i].Wei != Dist[v] || e[i].Cap - e[i].Flow <= 0)
continue;
Cur[u] = i;
Delta = Widen(v, Min(Limit - Used, e[i].Cap - e[i].Flow));
Used += Delta, e[i].Flow += Delta, e[i ^ 1].Flow -= Delta;
if(Used == Limit)
break;
}
Flag[u] = false;
return Used;
} void Dinic() {
Flow = 0, Cost = 0;
Type Delta;
while(spfa()) {
for(int i = 1; i <= n; i++)
Cur[i] = head[i];
Delta = Widen(s, INF);
Flow += Delta, Cost += Delta * Dist[t];
}
} #undef Type
} Flow_Graph;

spfa + Dijkstra + EK.

时间复杂度稳定,不会被卡。呃不会被卡吧。

struct Minimum_Cost_Maximum_Flow {
#define Type int
struct edge {
int v, nxt;
Type Wei, Cap, Flow;
edge() {}
edge(int V, int Nxt, Type C, Type W, Type F) {
v = V, nxt = Nxt, Cap = C, Wei = W, Flow = F;
}
} e[MAXM << 1];
int head[MAXM << 1], cnt = 0;
void Add_Edge(int u, int v, Type c, Type w) {
e[cnt] = edge(v, head[u], c, w, 0);
head[u] = cnt++;
e[cnt] = edge(u, head[v], 0, -w, 0);
head[v] = cnt++;
} struct node {
int x;
Type dis;
node() {}
node(int X, Type Dis) {
x = X, dis = Dis;
}
friend bool operator < (node One, node TheOther) {
return One.dis > TheOther.dis;
}
}; struct Back {
int Pre, id;
Back() {}
Back(int P, int Id) {
Pre = P, id = Id;
}
} Last[MAXN]; int Cur[MAXN], n, s, t;
bool vis[MAXN], Flag[MAXN];
Type Dist[MAXN], Aug[MAXN], h[MAXN], Flow, Cost; void init(int N, int S, int T) {
n = N, s = S, t = T, cnt = 0;
for(int i = 1; i <= n; i++)
head[i] = -1;
} void spfa(int s, int t) {
for(int i = 1; i <= n; i++)
h[i] = INF, vis[i] = false;
h[s] = 0, vis[s] = true;
queue<int> q;
q.push(s);
while(!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for(int i = head[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
if(e[i].Cap - e[i].Flow > 0 && h[v] > h[u] + e[i].Wei) {
h[v] = h[u] + e[i].Wei;
if(!vis[v])
vis[v] = true, q.push(v);
}
}
}
} bool Dijkstra(int s, int t) {
for(int i = 1; i <= n; i++)
Dist[i] = INF, Last[i] = Back(-1, -1), vis[i] = false, Aug[i] = INF;
priority_queue<node> q;
Dist[s] = 0;
q.push(node(s, Dist[s]));
while(!q.empty()) {
int u = q.top().x; q.pop();
if(vis[u])
continue;
vis[u] = true;
for(int i = head[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
if(e[i].Cap - e[i].Flow > 0 && Dist[v] > Dist[u] + e[i].Wei + h[u] - h[v]) {
Last[v] = Back(u, i);
Dist[v] = Dist[u] + e[i].Wei + h[u] - h[v];
Aug[v] = Min(Aug[u], e[i].Cap - e[i].Flow);
q.push(node(v, Dist[v]));
}
}
}
return Dist[t] != INF;
} void EK() {
Flow = 0, Cost = 0;
spfa(s, t);
while(Dijkstra(s, t)) {
Flow += Aug[t];
Cost += Aug[t] * (Dist[t] + h[t]);
int pos = t;
while(pos != s) {
e[Last[pos].id].Flow += Aug[t];
e[Last[pos].id ^ 1].Flow -= Aug[t];
pos = Last[pos].Pre;
}
for(int i = 1; i <= n; i++)
h[i] += Dist[i];
}
} #undef Type
} Flow_Graph;

Kuhn-Munkres.

最大匹配板子。当然你也可以直接 Dinic。

struct Bipartite_Graph {
struct edge {
int v, nxt;
edge() {}
edge(int V, int Nxt) {
v = V, nxt = Nxt;
}
} e[MAXM << 1];
int head[MAXN], n, m, cnt;
void Add_Edge(int u, int v) {
e[cnt] = edge(v, head[u]);
head[u] = cnt++;
}
int Mat[MAXN][2], Tim[MAXN], tot; void init(int N, int M) {
n = N, m = M;
for(int i = 1; i <= n; i++)
head[i] = -1, Tim[i] = 0, Mat[i][0] = 0, Mat[i][1] = 0;
cnt = 0, tot = 0;
} bool dfs(int u) {
if (Tim[u] == tot)
return false;
Tim[u] = tot;
for (int i = head[u], v; ~i; i = e[i].nxt) {
v = e[i].v;
if (!Mat[v][1] || dfs(Mat[v][1])) {
Mat[v][1] = u, Mat[u][0] = v;
return true;
}
}
return false;
} int calc() {
int ans = 0;
for (int i = 1; i <= m; i++)
Mat[i][1] = 0;
for (int i = 1; i <= n; i++)
Tim[i] = 0, Mat[i][0] = 0;
for (int i = n; i >= 1; i--) {
tot++;
ans += dfs(i);
}
return ans;
}
} Graph;

KM.

最小权最大匹配。

int n, m;
bool Vis[MAXN];
int Mat[MAXN], fa[MAXN];
LL w[MAXN][MAXN], Slack[MAXN], Val[MAXN][2]; void bfs(int S) {
for(int i = 0; i <= n; i++)
Slack[i] = INF, Vis[i] = false;
LL d;
int pos = 0, p, u;
for(Mat[pos] = S; Mat[pos]; pos = p) {
Vis[pos] = true, u = Mat[pos], d = INF;
for(int v = 1; v <= n; v++) {
if(Vis[v])
continue;
if(Val[u][0] + Val[v][1] - w[u][v] < Slack[v]) {
Slack[v] = Val[u][0] + Val[v][1] - w[u][v];
fa[v] = pos;
}
if(Slack[v] < d) {
d = Slack[v];
p = v;
}
}
for(int v = 0; v <= n; v++)
if(Vis[v])
Val[Mat[v]][0] -= d, Val[v][1] += d;
else
Slack[v] -= d;
}
for(; pos; pos = fa[pos])
Mat[pos] = Mat[fa[pos]];
} LL KM() {
LL res = 0;
for(int i = 1; i <= n; i++)
bfs(i);
for(int i = 1; i <= n; i++)
res += w[Mat[i]][i];
return res;
}

Template -「网络流 & 二分图」的更多相关文章

  1. Template -「整体二分」

    写的简单.主要是留给自己做复习资料. 「BZOJ1901」Dynamic Rankings. 给定一个含有 \(n\) 个数的序列 \(a_1,a_2 \dots a_n\),需要支持两种操作: Q ...

  2. Template -「矩阵 - 行列式」

    #include <cstdio> int Abs(int x) { return x < 0 ? -x : x; } int Max(int x, int y) { return ...

  3. [loj #6003]「网络流 24 题」魔术球 二分图最小路径覆盖,网络流

    #6003. 「网络流 24 题」魔术球 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据 ...

  4. LOJ6000 - 「网络流 24 题」搭配飞行员

    原题链接 题意简述 求二分图的最大匹配. 题解 这里写的是匈牙利算法. 表示节点的当前匹配. 为真表示在这一轮匹配中,无法给节点一个新的匹配.所以如果为真就不用再dfs它了,直接continue就好. ...

  5. LibreOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题

    #6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  6. LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图

    #6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  7. LibreOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

    #6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  8. 【刷题】LOJ 6227 「网络流 24 题」最长k可重线段集问题

    题目描述 给定平面 \(\text{xoy}\) 上 \(n\) 个开线段组成的集合 \(\text{I}\) ,和一个正整数 \(k\) ,试设计一个算法. 从开线段集合 \(\text{I}\) ...

  9. 「THUWC 2017」随机二分图

    「THUWC 2017」随机二分图 解题思路 : 首先有一个 \(40pts\) 的做法: 前 \(20pts\) 暴力枚举最终的匹配是怎样的,check一下计算方案数,后 \(20pts\) 令 \ ...

随机推荐

  1. ucore lab7 同步互斥机制 学习笔记

    管程的设计实在是精妙,初看的时候觉得非常奇怪,这混乱的进程切换怎么能保证同一时刻只有一个进程访问管程?理清之后大为赞叹,函数中途把前一个进程唤醒后立刻把自己挂起,完美切换.后一个进程又在巧妙的时机将自 ...

  2. sa-token client登录逻辑

  3. Markdown基础语法(上)

    前言 按照官方文档,和根据自己所用和所理解所写 一.标题语法 一级标题最大,六级标题最小 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标 ...

  4. Mac 手动安装 bee工具

    前因: 1.go升级到1.16以后,bee官网给的安装方法(go get XXX)不好使,需要指定version. 2.指定 go get XXX@v2.0.0 可以下载,但是bee工具还是用不了:c ...

  5. mysql5.7介绍和安装

    环境准备: 1.关闭防火墙和selinux systemctl stop firewalldsystemctl stop SElinux 2. 如果安装过mariadb需要停止且卸载服务 system ...

  6. 基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

    在前面介绍的SqlSugar的相关查询处理操作中,我们主要以单表的方式生成相关的实体类,并在查询的时候,对单表的字段进行条件的对比处理,从而返回对应的数据记录.本篇随笔介绍在一些外键或者中间表的处理中 ...

  7. python之生成器与模块

    目录 生成器对象 自定义range方法 生成器表达式 模块 简介 模块的导入方式 第一种:import ... 第二种:from ... import ... 补充 生成器对象 生成器对象其实本质还是 ...

  8. 2020.12.12【NOIP提高B组】模拟 总结

    第一次来 B 组做,虚的很 T1: 容斥原理 比赛时也打了个大致,但挂了,只有 50 分. 赛后重构了一下代码,AC \(UPDATE:2020/12/13\ \ \ 14:10\) 思路: 像前缀和 ...

  9. 腾讯云数据库TDSQL-大咖论道 | 基础软件的过去、现在、未来

    近十年来,中国基础软件发展势头迅猛,市场前景看高,越来越多的企业也正在进行基础软件升级.那中国基础软件行业目前在国际市场上有什么优势,面临哪些困境,以及未来基础软件行业会如何发展呢?腾讯云数据库邀请沙 ...

  10. ExtJS 布局-Absolute布局(Absolute layout)

    更新记录: 2022年5月31日 发布本篇 1.说明 使用xy配置项设置子组件在父容器中绝对位置,本质是将子组件的CSS的position设置为absolute,然后使用x和y配置项映射到CSS的to ...