网络流专题:点击打开链接
一、最大流之增广路算法
这个博客讲解放入挺详细的:点击打开链接
前向弧:离开点u的有向弧
后向弧:进入点u的有向弧
【恩~有一点我觉得有必要记录一下】
建立这些后向弧的必要性:
如果不建立后向边就容易出现上面这种情况,结果会偏小,路径是:1->2->5、1->2->3->5、1->3->5。
建立后向边之后,路径会增加一条:1->2->5、1->2->3->5、1->3->2->4->5、1->3->5。
2->3流量是1,3->2流量是1,相当于就没有流过。
模板题:【hdu 1532】
1、EdmondsKarp
struct Edge {
int from, to, cap, flow;
Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f){}
};
struct EdmondsKarp {
int n, m;
vector<Edge> edges;
vector<int> G[maxn];
int a[maxn];
int p[maxn];
void init(int n) {
for(int i=0; i<n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));//反向弧
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
int Maxflow(int s, int t) {
int flow = 0;
for(;;){
memset(a, 0, sizeof(a));
queue<int>Q;
Q.push(s);
a[s] = INF;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
int len = (int)G[x].size();
for(int i=0; i<len; i++) {
Edge& e = edges[G[x][i]];
if(!a[e.to] && e.cap>e.flow) {
p[e.to] = G[x][i];
a[e.to] = min(a[x], e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]) break;
}
if(!a[t]) break;
for(int u = t; u!=s; u=edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
}
flow += a[t];
}
return flow;
}
};
2、Dinic递归:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
using namespace std;
const int maxn=1e3+10;
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow;
Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f){}
};
vector<Edge> edges;
vector<int>G[maxn];
bool vis[maxn];
int dis[maxn];
int cur[maxn];
void init(int n) {
for(int i=0; i<n; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap) {
edges.push_back(Edge(from, to, cap, 0));
edges.push_back(Edge(to, from, 0, 0));//反向弧
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BFS(int s, int t) {
memset(vis, 0, sizeof(vis));
int n, m;
queue<int> Q;
Q.push(s);
dis[s] = 0;
vis[s] = 1;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = 0; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
dis[e.to] = dis[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int DFS(int x, int t, int a){
if(x == t || a == 0) return a;
int flow = 0, f;
for(int& i = cur[x]; i < G[x].size(); i++) {
Edge& e = edges[G[x][i]];
if(dis[x] + 1 == dis[e.to] && (f = DFS(e.to, t, min(a, e.cap-e.flow))) > 0) {
e.flow += f;
edges[G[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int Maxflow(int s, int t){
int flow = 0;
while(BFS(s, t)) {
memset(cur, 0, sizeof(cur));
flow += DFS(s, t, INF);
}
return flow;
}
int main(){
int m, n;
while(~scanf("%d%d", &m, &n)) {
init(n);
for(int i=0; i<m; i++){
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
AddEdge(u, v, c);
}
printf("%d\n", Maxflow(1, n));
}
return 0;
}
3、Dinic非递归:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
//点标 [0,n]
const int N = 200010;
const int M = 500010;
const int INF = ~0u >> 2;
template<class T>
struct Max_Flow {
int n;
int Q[N], sign;
int head[N], level[N], cur[N], pre[N];
int nxt[M], pnt[M], E;
T cap[M];
void Init(int n) {
this->n = n+1;
E = 0;
std::fill(head, head + this->n, -1);
}
//有向rw 就= 0
void add(int from, int to, T c, T rw) {
pnt[E] = to;
cap[E] = c;
nxt[E] = head[from];
head[from] = E++;
pnt[E] = from;
cap[E] = rw;
nxt[E] = head[to];
head[to] = E++;
}
bool Bfs(int s, int t) {
sign = t;
std::fill(level, level + n, -1);
int *front = Q, *tail = Q;
*tail++ = t; level[t] = 0;
while(front < tail && level[s] == -1) {
int u = *front++;
for(int e = head[u]; e != -1; e = nxt[e]) {
if(cap[e ^ 1] > 0 && level[pnt[e]] < 0) {
level[pnt[e]] = level[u] + 1;
*tail ++ = pnt[e];
}
}
}
return level[s] != -1;
}
void Push(int t, T &flow) {
T mi = INF;
int p = pre[t];
for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
mi = std::min(mi, cap[p]);
}
for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {
cap[p] -= mi;
if(!cap[p]) {
sign = pnt[p ^ 1];
}
cap[p ^ 1] += mi;
}
flow += mi;
}
void Dfs(int u, int t, T &flow) {
if(u == t) {
Push(t, flow);
return ;
}
for(int &e = cur[u]; e != -1; e = nxt[e]) {
if(cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {
pre[pnt[e]] = e;
Dfs(pnt[e], t, flow);
if(level[sign] > level[u]) {
return ;
}
sign = t;
}
}
}
T Dinic(int s, int t) {
pre[s] = -1;
T flow = 0;
while(Bfs(s, t)) {
std::copy(head, head + n, cur);
Dfs(s, t, flow);
}
return flow;
}
};
Max_Flow <int>F;
int main(){
int t, n, m;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
F.Init(n);
int s = 1, t = n;
for(int i=0; i<m; i++){
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
F.add(u, v, c, c);
}
printf("%d\n", F.Dinic(s, t));
}
return 0;
}
【HDU 4280】 Island Transport 用Dinic非递归做能对,递归超时
易错例题:
有n头牛,f中食物,d种饮料,每头牛都只吃固定的几种食物跟饮料,问最多有几头牛能吃到一种食物,一种饮料
注意点就是建图的时候n个点要拆成2*n个点,免得一头牛吃了多食物跟饮料。
二、最小割最大流
三、最小费用最大流
和Edmonds-Karp类似,但每次用Bellman-Ford算法而非BFS找增广路。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <map>
using namespace std;
const int maxn=1e3+10;
const int INF = 0x3f3f3f3f;
struct Edge {
int from, to, cap, flow, cost;
Edge(int u, int v, int c, int f, int w):from(u), to(v), cap(c), flow(f), cost(w){}
};
vector<Edge> edges;
vector<int> G[maxn];
int inq[maxn];
int d[maxn];
int p[maxn];
int a[maxn];
void init(){
for(int i=0; i<maxn; i++) G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, int cost) {
edges.push_back(Edge(from, to, cap, 0, cost));
edges.push_back(Edge(to, from, 0, 0, -cost));
int m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s, int t, int& flow, long long& cost) {
memset(inq, 0, sizeof(inq));
memset(d, INF, sizeof(d));
d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
queue<int>Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i = 0; i < G[u].size(); i++) {
Edge& e = edges[G[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]){
Q.push(e.to);
inq[e.to] = 1;
}
}
}
}
if(d[t] == INF) return false;
flow += a[t];
cost += (long long)d[t] * (long long)a[t];
for(int u = t; u != s; u = edges[p[u]].from) {
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
}
return true;
}
//需要保证初始网络中没有负权圈
int MincostMaxflow(int s, int t, long long& cost) {
int flow = 0;
cost = 0;
while(BellmanFord(s, t, flow, cost));
return flow;
}
int main() {
int n, m;
while(~scanf("%d%d", &n, &m)){
init();
for(int i=0; i<m; i++){
int u, v, f, c;
scanf("%d%d%d%d", &u, &v, &f, &c);
AddEdge(u, v, f, c);
}
long long cost=0;
int flow = MincostMaxflow(1, n, cost);
printf("%d %lld\n", flow, cost);
}
return 0;
}