文章目录
一、最大流 & 最小割问题
1. 模板
1.1 Ford-Fulkerson
由于这个算法复杂度玄学,所以会 T 掉两个点。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 5005
#define INF 0x3f3f3f3f
int n, m, s, t;
int vis[MAXN];
int head[MAXN], cnt;
struct node{
int to, w;
int next;
}map[MAXN*2];
void add(int u, int v, int w)
{
map[cnt] = (node){v, w, head[u]};
head[u] = cnt++;
}
int dfs(int u, int flow)
{
if (u == t) return flow;
vis[u] = 1;
for (int k=head[u];k!=-1;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
int delta = 0;
if(!vis[v] && w > 0 && (delta = dfs(v, min(flow, w))) != -1)
{
map[k].w -= delta;
map[k ^ 1].w += delta;
return delta;
}
}
return -1;
}
long long FF(void)
{
int delta = 0;
long long ans = 0;
while ((delta = dfs(s, INF)) != -1)
{
memset(vis, 0, sizeof(vis));
ans += delta;
}
return ans;
}
int main(void)
{
memset(head, -1, sizeof(head));
cin >> n >> m >> s >> t;
for (int i=1;i<=m;i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, 0);
}
cout << FF() << endl;
return 0;
}
1.2 Edmond-Karp
#include <queue>
#include <string.h>
#include <stdio.h>
#include <iostream>
using namespace std;
#define MAXN 5005
#define INF 0x3f3f3f3f
int n, m, s, t;
int last[MAXN], flow[MAXN];
int head[MAXN], cnt;
struct node{
int to, w;
int next;
}map[MAXN*2];
void add(int u, int v, int w)
{
map[cnt] = (node){v, w, head[u]};
head[u] = cnt++;
}
bool bfs(void)
{
memset(last, -1, sizeof last);
queue <int>que;
que.push(s);
flow[s] = INF;
while (!que.empty())
{
int u = que.front();
que.pop();
if (u == t) break;
for (int k=head[u];k!=-1;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (w != 0 && last[v] == -1)
{
last[v] = k;
flow[v] = min(w, flow[u]);
que.push(v);
}
}
}
return last[t] != -1;
}
long long EK()
{
long long ans = 0;
while (bfs())
{
ans += flow[t];
for (int i=t;i!=s;i=map[last[i] ^ 1].to)
{
map[last[i]].w -= flow[t];
map[last[i] ^ 1].w += flow[t];
}
}
return ans;
}
int main(void)
{
memset(head, -1, sizeof head);
cin >> n >> m >> s >> t;
for (int i=1;i<=m;i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, 0);
}
cout << EK() << endl;
return 0;
}
1.3 Dinic
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 5005
#define INF 0x3f3f3f3f
int n, m, s, t;
int temp[MAXN], dep[MAXN];
int head[MAXN], cnt;
struct node{
int to, w, next;
}map[MAXN*2];
void add(int u, int v, int w)
{
map[cnt] = (node){v, w, head[u]};
head[u] = cnt++;
}
int bfs()
{
memset(dep, -1, sizeof dep);
memcpy(temp, head, sizeof head);
queue <int> que;
que.push(s);
dep[s] = 0;
while (!que.empty())
{
int u = que.front();
que.pop();
for (int k=head[u];k!=-1;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == -1)
{
dep[v] = dep[u] + 1;
que.push(v);
}
}
}
return dep[t] != -1;
}
int dfs(int u, int flow)
{
if (u == t)
{
return flow;
}
int rmnd = flow;
for (int k=temp[u];k!=-1 && rmnd;k=map[k].next)
{
temp[u] = k;
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == dep[u] + 1)
{
int delta = dfs(v, min(rmnd, w));
rmnd -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
}
}
return flow - rmnd;
}
long long Dinic(void)
{
long long ans = 0;
while (bfs())
{
ans += dfs(s, INF);
}
return ans;
}
int main(void)
{
memset(head, -1, sizeof head);
cin >> n >> m >> s >> t;
for (int i=1;i<=m;i++)
{
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
add(v, u, 0);
}
cout << Dinic() << endl;
return 0;
}
2. 题目
(1) P2756 飞行员配对方案问题
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 10005
#define INF 0x3f3f3f3f
int n, m;
int vis[MAXN], dep[MAXN], temp[MAXN], match[MAXN];
int head[MAXN], cnt = 1;
struct node{
int to, w, next;
}map[MAXN * 2];
void add(int u, int v, int w)
{
map[++cnt] = (node){v, w, head[u]};
head[u] = cnt;
}
bool bfs()
{
memset(dep, -1, sizeof dep);
memcpy(temp, head, sizeof head);
queue <int>que;
que.push(0);
dep[0] = 0;
while (!que.empty())
{
int u = que.front();
que.pop();
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == -1)
{
dep[v] = dep[u] + 1;
que.push(v);
}
}
}
return dep[m+1] != -1;
}
int dfs(int u, int flow)
{
if (u == m + 1) return flow;
int rmnd = flow;
for (int k=temp[u];k;k=map[k].next)
{
temp[u] = k;
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == dep[u] + 1)
{
int delta = dfs(v, min(w, rmnd));
rmnd -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
if (!map[k].w) match[u] = v;
if (!rmnd) break;
}
}
return flow - rmnd;
}
int Dinic()
{
int ans = 0;
while (bfs())
{
ans += dfs(0, INF);
}
return ans;
}
int main(void)
{
cin >> n >> m;
int u, v;
cin >> u >> v;
while (u!=-1 && v!=-1)
{
add(u, v, 1);
add(v, u, 0);
cin >> u >> v;
}
for (int i=1;i<=n;i++)
{
add(0, i, 1);
add(i, 0, 0);
}
for (int i=n+1;i<=m;i++)
{
add(i, m+1, 1);
add(m+1, i, 0);
}
cout << Dinic() << endl;
for (int i=1;i<=n;i++)
{
if (match[i])
{
cout << i << " " << match[i] << endl;
}
}
return 0;
}
顺带一提,这道题还可以用二分图匹配来做。
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 10005
int n, m, ans;
int vis[MAXN];
int match[MAXN];
int head[MAXN], cnt;
struct node{
int to, next;
}map[MAXN * 2];
void add(int u, int v)
{
map[++cnt] = (node){v, head[u]};
head[u] = cnt;
}
bool Hungary(int u)
{
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
if (!vis[v])
{
vis[v] = 1;
if (!match[v] || Hungary(match[v]))
{
match[v] = u;
return 1;
}
}
}
return 0;
}
int main(void)
{
cin >> n >> m;
int u, v;
cin >> u >> v;
while(u!=-1 && v!=-1)
{
add(u, v);
cin >> u >> v;
}
for (int i=1;i<=n;i++)
{
memset(vis, 0, sizeof vis);
ans += Hungary(i);
}
cout << ans << endl;
for (int i=n+1;i<=m;i++)
{
if (match[i])
cout << match[i] << " " << i << endl;
}
return 0;
}
(2) P2763 试题库问题
#include <stdio.h>
#include <string.h>
#include <queue>
#include <iostream>
using namespace std;
#define MAXN 200005
#define t n+K+1
#define INF 0x3f3f3f3f
int K, n, m, cnt = 1, s = 0;
int dep[MAXN], temp[MAXN * 2], head[MAXN * 2], vis[MAXN];
struct node{
int to, next, w;
}map[MAXN*2];
void add(int u, int v, int w)
{
map[++cnt] = (node){v, head[u], w};
head[u] = cnt;
}
bool bfs(void)
{
memset(dep, -1, sizeof dep);
memcpy(temp, head, sizeof head);
queue <int> que;
que.push(s);
dep[s] = 0;
while (!que.empty())
{
int u = que.front();
que.pop();
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == -1)
{
dep[v] = dep[u] + 1;
que.push(v);
}
}
}
return dep[t] != -1;
}
int dfs(int u, int flow)
{
if (u == t)
{
return flow;
}
int rmnd = flow;
for (int k = temp[u];k && rmnd;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
temp[u] = k;
if (w && dep[v] == dep[u] + 1)
{
int delta = dfs(v, min(rmnd, w));
rmnd -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
}
}
return flow - rmnd;
}
int Dinic(void)
{
int ans = 0;
while (bfs())
{
ans += dfs(s, INF);
}
return ans;
}
void print(int u)
{
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (v == t) continue;
if (w == 1 && !vis[v])
{
cout << v << " ";
vis[v] = 1;
}
}
}
int main(void)
{
cin >> K >> n;
for (int i=1;i<=K;i++)
{
int knum;
cin >> knum;
m += knum;
add(i+n, t, knum);
add(t, i+n, 0);
}
for (int i=1;i<=n;i++)
{
int num;
cin >> num;
for (int j=1;j<=num;j++)
{
int ki;
cin >> ki;
add(i, ki+n, 1);
add(ki+n, i, 0);
}
add(s, i, 1);
add(i, s, 0);
}
if (Dinic() != m)
{
cout << "No Solution!";
return 0;
}
for (int i=1;i<=K;i++)
{
cout << i << ": ";
print(i + n);
cout << endl;
}
return 0;
}
当然,这道题也可以用匈牙利算法做,但是不是主流方法,这里就不给出代码了。 (其实是因为没有这么做)
二、最小费用最大流问题
1. 模板
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 50005
#define INF 1e9
int n, m, s, t, cost;
int vis[MAXN], dis[MAXN];
int head[MAXN],cnt=1;
struct node{
int to, w, next, f;
}map[MAXN * 2];
void add(int u, int v, int w, int f)
{
map[++cnt] = (node){v, w, head[u], f};
head[u] = cnt;
}
bool SPFA()
{
memset(vis, 0, sizeof vis);
for (int i=1;i<=n;i++) dis[i] = INF;
queue <int> que;
dis[s] = 0;
que.push(s);
while (!que.empty())
{
int u = que.front();
que.pop();
vis[u] = 0;
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
int f = map[k].f;
if (dis[v] > dis[u] + f && w)
{
dis[v] = dis[u] + f;
if (!vis[v])
{
vis[v] = 1;
que.push(v);
}
}
}
}
return dis[t] != INF;
}
int dfs(int u, int flow)
{
if (u == t) return flow;
int temp = flow;
vis[u] = 1;
for (int k=head[u];k && temp;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
int f = map[k].f;
if (w && dis[v] == dis[u] + f && !vis[v])
{
int delta = dfs(v, min(temp, w));
temp -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
cost += delta * f;
}
}
vis[u] = 0;
return flow - temp;
}
int Dinic(void)
{
int ans = 0;
while (SPFA())
{
memset(vis, 0, sizeof vis);
ans += dfs(s, INF);
}
return ans;
}
int main(void)
{
cin >> n >> m >> s >> t;
for (int i=1;i<=m;i++)
{
int u, v, w, f;
cin >> u >> v >> w >> f;
add(u, v, w, f);
add(v, u, 0, -f);
}
cout << Dinic() << " " << cost << endl;
return 0;
}
2. 题目
(2) P4015 运输问题
#include <queue>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 10005
#define INF 0x3f3f3f3f
int m, n, s = 0, t = 201, cost;
int cnt = 1;
int head[MAXN], dis[MAXN], vis[MAXN], val[MAXN];
struct node{
int to, w, w2, next, f, f2;
void init()
{
w = w2;
f = f2;
}
}map[MAXN*2];
void add(int u, int v, int w, int f)
{
map[++cnt] = (node){v, w, w, head[u], f, f};
head[u] = cnt;
}
bool bfs(int q)
{
memset(dis, 0x3f, sizeof dis);
memset(vis, 0, sizeof vis);
queue <int> que;
que.push(s);
dis[s] = 0;
vis[s] = 1;
while (!que.empty())
{
int u = que.front();
que.pop();
vis[u] = 0;
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
int f = map[k].f * q;
if (w && dis[u] + f < dis[v])
{
dis[v] = f + dis[u];
if (!vis[v])
{
vis[v] = 1;
que.push(v);
}
}
}
}
return dis[t] != INF;
}
int dfs(int u, int flow, int q)
{
if (u == t)
{
return flow;
}
int rmnd = flow;
vis[u] = 1;
for (int k=head[u];k && rmnd;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
int f = map[k].f * q;
if (w && dis[v] == dis[u] + f && !vis[v])
{
int delta = dfs(v, min(rmnd, w), q);
//cout << u << " " << v << " " << w << endl;
rmnd -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
cost += delta * f * q;
}
}
vis[u] = 0;
return flow - rmnd;
}
void Dinic(int k)
{
cost = 0;
while (bfs(k))
{
memset(vis, 0, sizeof vis);
dfs(s, INF, k);
}
}
int main(void)
{
cin >> m >> n;
for (int i=1;i<=m;i++)
{
cin >> val[i];
add(s, i, val[i], 0);
add(i, s, 0, 0);
}
for (int j=1;j<=n;j++)
{
cin >> val[j+100];
add(j+100, t, val[j+100], 0);
add(t, j+100, 0, 0);
}
for (int i=1;i<=m;i++)
{
for (int j=1;j<=n;j++)
{
int f;
cin >> f;
add(i, j+100, INF, f);
add(j+100, i, 0, -f);
}
}
Dinic(1);
cout << cost << endl;
for (int i=1;i<=cnt;i++)
{
map[i].init();
}
Dinic(-1);
cout << cost;
return 0;
}
三、最大权闭合子图问题
1. 建图方法
-
源点向所有正权点连结一条容量为权值的边
-
所有负权点向汇点连结一条容量为权值绝对值的边
-
保留原图中所有的边,容量为正无穷
在最小割图上,如果割掉 s s s 和 u u u 之间的边,代表不选择 u u u 进入子图,如果割掉 v v v 和 t t t 之间的边,代表选择 v v v 进入子图。
2. 题目
(3) P2762 太空飞行计划问题
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define MAXN 2500
#define INF 0x3f3f3f3f
int n, m, tot;
int cnt = 1;
int s = 0, t = 101;
int vis[MAXN], head[MAXN], dep[MAXN], temp[MAXN], dis[MAXN];
struct node{
int to, w, next;
}map[MAXN];
void add(int u, int v, int w)
{
map[++cnt] = (node){v, w, head[u]};
head[u] = cnt;
}
bool bfs(void)
{
memset(dep, -1, sizeof dep);
memset(dis, -1, sizeof dis);
memcpy(temp, head, sizeof head);
queue <int>que;
que.push(s);
dep[s] = 0;
while (!que.empty())
{
int u = que.front();
que.pop();
for (int k=head[u];k;k=map[k].next)
{
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == -1)
{
dis[v] = 1;
dep[v] = dep[u] + 1;
que.push(v);
}
}
}
return dep[t] != -1;
}
int dfs(int u, int flow)
{
if (u == t)
{
return flow;
}
int rmnd = flow;
temp[u] = head[u];
for (int k=temp[u];k && rmnd;k=map[k].next)
{
temp[u] = k;
int v = map[k].to;
int w = map[k].w;
if (w && dep[v] == dep[u] + 1)
{
int delta = dfs(v, min(rmnd, w));
//cout << u << " " << v << " " << w << endl;
rmnd -= delta;
map[k].w -= delta;
map[k ^ 1].w += delta;
}
}
return flow - rmnd;
}
int Dinic(void)
{
int ans = 0;
while (bfs())
{
ans += dfs(s, INF);
}
return ans;
}
void read(void)
{
cin >> n >> m;
for (int i=1;i<=n;i++)
{
int sponsor;
cin >> sponsor;
tot += sponsor;
add(s, i+50, sponsor);
add(i+50, s, 0);
char tools[10000];
memset(tools,0,sizeof tools);
cin.getline(tools,10000);
int ulen=0, tool;
while (sscanf(tools + ulen,"%d",&tool) == 1)//之前已经用scanf读完了赞助商同意支付该实验的费用
{//tool是该实验所需仪器的其中一个
//这一行,你可以将读进来的编号进行储存、处理,如连边。
add(i+50, tool, INF);
add(tool, i+50, 0);
if (tool==0)
{
ulen++;
}
else
{
while (tool)
{
tool/=10;
ulen++;
}
}
ulen++;
}
}
for (int i=1;i<=m;i++)
{
int pay;
cin >> pay;
add(i, t, pay);
add(t, i, 0);
}
}
int main(void)
{
read();
int ans = Dinic();
for (int i=1;i<=n;i++)
{
if (dep[i+50] != -1)
{
cout << i << " ";
}
}
cout << endl;
for (int j=1;j<=m;j++)
{
if (dis[j] != -1)
{
cout << j << " ";
}
}
cout << endl << tot - ans;
return 0;
}
持续更新中。。。