本文不涉及讲解,仅罗列各种算法模板(都是自己写的,不一定最优,且一个算法不一定只有一种)——不定期更新
目录
- Edmond-Karp()——包含邻接矩阵,邻接表,储存边三种
- Dinic()——包含基础与当前弧优化两种
- 推送重贴标签()——一种
- 前置重贴标签()——一种
- 注:最后两种来自与《算法导论》,不一定保证最优实现,且该两种算法下界大致为,故要谨慎使用!!(以及残存容量实时更新,不单独计算并允许双向边存在)
Edmond-Karp算法
1.邻接链表(第一次写网络流的最好尝试)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
int N, M, st, se;
int cap[205][205], pre[205];
bool vis[205];
int Edmonds_Karp(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
for(i = 1; i <= M; i++){
int x, y, w;
cin >> x >> y >> w;
cap[x][y] = w;
}
cout << Edmonds_Karp(st, se) << endl;
return 0;
}
bool bfs(int s, int t);//寻找残存网络中最短增广路
int Edmonds_Karp(int s, int t){
int i, cf_min, max_flow;
max_flow = 0;
while(bfs(s, t)){
cf_min = 1e9 + 7;
for(i = t; i != s; i = pre[i])
cf_min = min(cf_min, cap[pre[i]][i]);
for(i = t; i != s; i = pre[i]){
cap[pre[i]][i] -= cf_min;
cap[i][pre[i]] += cf_min;
}
max_flow += cf_min;
}
return max_flow;
}
bool bfs(int s, int t){
int i;
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s), vis[s] = true;
while(!Q.empty()){
auto u = Q.front(); Q.pop();
for(i = 1; i <= N; i++){
if(!vis[i] && cap[u][i] > 0){
Q.push(i), vis[i] = true;
pre[i] = u;
if(i == t) return true;
}
}
}
return false;
}
2.邻接表
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;
struct edge {
int next, now, to, c;
} e[MAXM * 2];
int head[MAXN], cnt_adj;
void add_edge(int x, int y, int z);
int N, M, st, se;
int Edmonds_Karp(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
cnt_adj = 1;
for(i = 1; i <= M; i++){
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, 0);
}
cout << Edmonds_Karp(st, se) << endl;
return 0;
}
int pre[MAXN];
bool EK_bfs(int s, int t);
int Edmonds_Karp(int s, int t){
int maxflow = 0;
while(EK_bfs(s, t)){
int i, cf_min = 1e9 + 7;
for(i = pre[t]; i; i = pre[e[i].now]){
cf_min = min(cf_min, e[i].c);
}
for(i = pre[t]; i; i = pre[e[i].now]){
e[i].c -= cf_min;
e[i ^ 1].c += cf_min;
}
maxflow += cf_min;
}
return maxflow;
}
bool vis[MAXN];
bool EK_bfs(int s, int t){
memset(vis, 0, sizeof(vis));
int i;
queue<int> Q;
Q.push(s), vis[s] = true;
while(!Q.empty()){
int u = Q.front(); Q.pop();
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(!vis[v] && cf){
Q.push(v), vis[v] = true;
pre[v] = i;
if(v == t) return true;
}
}
}
return false;
}
void add_edge(int x, int y, int z){
e[++cnt_adj].to = y;
e[cnt_adj].now = x;
e[cnt_adj].c = z;
e[cnt_adj].next = head[x];
head[x] = cnt_adj;
}
3.储存边
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;
//储存边与对于顶点的反向hash
struct node {
int u, v, c;
} e[MAXM * 2];
vector<int> hash_e[MAXN];
int N, M, st, se;
int pre[MAXN];
bool vis[MAXN];
int Edmonds_Karp(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i, j;
cin >> N >> M >> st >> se;
for(j = 0; j < M; j++){
i = 2 * j;
int x, y, z;
cin >> x >> y >> z;
e[i].u = x, e[i].v = y, e[i].c = z;
e[i ^ 1].u = y, e[i ^ 1].v = x;
hash_e[x].push_back(i);
hash_e[y].push_back(i ^ 1);
}
cout << Edmonds_Karp(st, se) << endl;
return 0;
}
bool EK_bfs(int s, int t);
int Edmonds_Karp(int s, int t){
int i, cap_min, maxflow;
maxflow = 0;
while(EK_bfs(s, t)){
cap_min = 1e9 + 7;
for(i = t; i != s; i = e[pre[i]].u)
cap_min = min(cap_min, e[pre[i]].c);
for(i = t; i != s; i = e[pre[i]].u){
e[pre[i]].c -= cap_min;
e[pre[i] ^ 1].c += cap_min;
}
maxflow += cap_min;
}
return maxflow;
}
bool EK_bfs(int s, int t){
memset(vis, 0, sizeof(vis));
int i, j;
queue<int> Q;
Q.push(s), vis[s] = true;
while(!Q.empty()){
auto u = Q.front(); Q.pop();
for(i = 0; i < (int)hash_e[u].size(); i++){
j = hash_e[u][i];
int v = e[j].v;
if(!vis[v] && e[j].c > 0){
Q.push(v), vis[v] = true;
pre[v] = j;
if(v == t) return true;
}
}
}
return false;
}
Dinic算法
1.基本写法
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;
struct edge {
int next, to, c;
} e[MAXM * 2];
int head[MAXN], cnt_adj;
void add_edge(int, int, int);
int N, M, st, se;
int Dinic(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
cnt_adj = 1;//2i-1与2i对应一组边,从2开始(不可从0)
for(i = 1; i <= M; i++){
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, 0);
}
cout << Dinic(st, se) << endl;
return 0;
}
int dep[MAXN];
bool Dinic_bfs(int s, int t);
int Dinic_dfs(int u, int cf_min, int t);
int Dinic(int s, int t){
int max_flow = 0;
while(Dinic_bfs(s, t))
while(int val = Dinic_dfs(s, 1e9 + 7, t))
max_flow += val;
return max_flow;
}
//分层
bool Dinic_bfs(int s, int t){
int i;
memset(dep, 0, sizeof(dep));
queue<int> Q;
Q.push(s), dep[s] = 1;
while(!Q.empty()){
auto u = Q.front(); Q.pop();
//cout << u << endl;
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
//cout << v << " " << cf << endl;
if(cf > 0 && !dep[v]){
dep[v] = dep[u] + 1;
Q.push(v);
}
}
//cout << endl;
}
//cout << endl;
if(!dep[t]) return false;
return true;
}
int Dinic_dfs(int u, int cf_min, int t){
if(u == t) return cf_min;
int i;
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(dep[v] == dep[u] + 1 && cf > 0){
int val = Dinic_dfs(v, min(cf_min, cf), t);
if(val > 0){//增广成功
e[i].c -= val;
e[i ^ 1].c += val;
return val;
}
}
}
return 0;
}
void add_edge(int x, int y, int z){
e[++cnt_adj].to = y;
e[cnt_adj].c = z;
e[cnt_adj].next = head[x];
head[x] = cnt_adj;
}
2.当前弧优化
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;
struct edge {
int next, to, c;
} e[MAXM * 2];
int head[MAXN], cnt_adj;
void add_edge(int x, int y, int z);
int N, M, st, se;
int Dinic(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
cnt_adj = 1;
for(i = 1; i <= M; i++){
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, 0);
}
cout << Dinic(st, se) << endl;
return 0;
}
int dep[MAXN], cur[MAXN];
bool Dinic_bfs(int s, int t);
int Dinic_dfs(int u, int cf_min, int t);
int Dinic(int s, int t){
int maxflow = 0;
while(Dinic_bfs(s, t)){
int i, val;
for(i = 1; i <= N; i++)
cur[i] = head[i];
while((val = Dinic_dfs(s, 1e9 + 7, t)))
maxflow += val;
}
return maxflow;
}
bool Dinic_bfs(int s, int t){
int i;
memset(dep, 0, sizeof(dep));
queue<int> Q;
Q.push(s), dep[s] = 1;
while(!Q.empty()){
auto u = Q.front(); Q.pop();
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(cf > 0 && !dep[v]){
dep[v] = dep[u] + 1;
Q.push(v);
}
}
}
if(!dep[t]) return false;
return true;
}
int Dinic_dfs(int u, int cf_min, int t){
if(u == t || !cf_min) return cf_min;
for(int &i = cur[u]; i; i = e[i].next){//取地址进行操作,实时更新
int v = e[i].to, cf = e[i].c;
if(cf > 0 && dep[v] == dep[u] + 1){
int val = Dinic_dfs(v, min(cf_min, cf), t);
if(val > 0){
e[i].c -= val;
e[i ^ 1].c += val;
return val;
}
}
}
return 0;
}
void add_edge(int x, int y, int z){
e[++cnt_adj].to = y;
e[cnt_adj].c = z;
e[cnt_adj].next = head[x];
head[x] = cnt_adj;
}
推送-重贴标签
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
struct edge {
int next, to, c;
} e[200005];
int head[10005], cnt_adj;
void add_edge(int x, int y, int z);
int N, M, st, se;
int Push_and_Relabel(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
cnt_adj = 1;
for(i = 1; i <= M; i++){
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, 0);
}
cout << Push_and_Relabel(st, se) << endl;
return 0;
}
struct node {
int h, e;
} p[10005];
void Init_Preflow(int s);
int check(int s, int t);
bool Push(int u);
void Relabel(int u);
int Push_and_Relabel(int s, int t){
int id;
Init_Preflow(s);
while((id = check(s, t))){
if(!Push(id))
Relabel(id);
}
return p[t].e;
}
int check(int s, int t){
int i;
for(i = 1; i <= N; i++)
if(i != s && i != t && p[i].e)
return i;
return 0;
}
void Init_Preflow(int s){
int i;
p[s].h = N;
for(i = head[s]; i; i = e[i].next){
int val = e[i].c;
p[s].e -= val;
p[e[i].to].e += val;
e[i].c -= val;
e[i ^ 1].c += val;
}
}
bool Push(int u){
bool flag = false;
int i;
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(cf && p[u].h == p[v].h + 1){
int val = min(p[u].e, cf);
p[u].e -= val;
p[v].e += val;
e[i].c -= val;
e[i ^ 1].c += val;
flag = true;
}
}
return flag;
}
void Relabel(int u){
int i, minn = 1e9 + 7;
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(cf)
minn = min(minn, p[v].h);
}
if(minn == 1e9 + 7)
minn = -1;
p[u].h = minn + 1;
}
void add_edge(int x, int y, int z){
e[++cnt_adj].to = y;
e[cnt_adj].c = z;
e[cnt_adj].next = head[x];
head[x] = cnt_adj;
}
前置重贴标签
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 1e4 + 5;
const int MAXM = 1e5 + 5;
struct edge {
int next, to, c, f, cf;
} e[MAXM * 2];
int head[MAXN], cnt_adj;
void add_edge(int x, int y, int z);
int N, M, st, se;
int height[MAXN], overflow[MAXN];
void Relabel_to_Front(int s, int t);
int main(){
ios::sync_with_stdio(false);
int i;
cin >> N >> M >> st >> se;
cnt_adj = 1;
for(i = 1; i <= M; i++){
int x, y, z;
cin >> x >> y >> z;
add_edge(x, y, z);
add_edge(y, x, 0);
}
Relabel_to_Front(st, se);
//for(i = 1; i <= N; i++)
// cout << overflow[i] << endl;
cout << overflow[se] << endl;
return 0;
}
struct linklist {
int val;
linklist *next, *pre;
};
void Discharge(int u);
void Init_Preflow(int s);
void Relabel_to_Front(int s, int t){
Init_Preflow(s);
int i;
linklist *head = new linklist;
linklist *NIL = new linklist;
head->next = head->pre = NIL;
head->val = NIL->val = -1;
for(i = 1; i <= N; i++)
if(i != s && i != t){
linklist *x = new linklist;
x->val = i;
x->next = head->next;
x->pre = head;
x->next->pre = x;
head->next = x;
}
linklist *p = head->next;
while(p->val != -1){
int u = p->val;
int old_height = height[u];
Discharge(u);
if(old_height < height[u]){
p->pre->next = p->next;
p->next->pre = p->pre;
p->next = head->next;
p->pre = head;
p->next->pre = p;
head->next = p;
}
p = p->next;
}
}
void Init_Preflow(int s){
int i;
//memset(height, 0, sizeof(height));
//memset(overflow, 0, sizeof(overflow));
//init e.f=0;
height[s] = N;
for(i = head[s]; i; i = e[i].next){
int val = e[i].c;
e[i].f = val;
overflow[s] -= val;
overflow[e[i].to] += val;
e[i].c -= val;
e[i ^ 1].c += val;
}
//for(i = 1; i <= N; i++)
// cout << overflow[i] << endl;
}
void Push(int u, int id);
void Relabel(int u);
void Discharge(int u){
int i;
i = head[u];
if(!i) return;
while(overflow[u]){
if(!i){
Relabel(u);
i = head[u];
}else{
int v = e[i].to, cf = e[i].c;
if(cf && height[u] == height[v] + 1)
Push(u, i);
i = e[i].next;
}
}
}
void Push(int u, int id){
int val = min(overflow[u], e[id].c);
e[id].c -= val;
e[id ^ 1].c += val;
overflow[u] -= val;
overflow[e[id].to] += val;
}
void Relabel(int u){
int i, minn = 1e9 + 7;
for(i = head[u]; i; i = e[i].next){
int v = e[i].to, cf = e[i].c;
if(cf)
minn = min(minn, height[v]);
}
if(minn == 1e9 + 7) minn = -1;
height[u] = minn + 1;
}
void add_edge(int x, int y, int z){
e[++cnt_adj].to = y;
e[cnt_adj].c = z;
e[cnt_adj].next = head[x];
head[x] = cnt_adj;
}