紫书上的代码,加了注释(EK算法)
#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 100 + 5;
using namespace std;
int n,m;
struct Edge{
int from, to, cap, flow;
Edge(int f, int t, int c, int fl):from(f),to(t),cap(c),flow(fl){}
};
struct EK{
int n,m;
vector<Edge> edges;
vector<int> G[maxn];//每个结点i连接的结点j 即在edges中的下标
int a[maxn];//当起点到i的可改进量
int pre[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 = (int)edges.size();
G[from].push_back(m-2);//连接的边的序号 从0开始
G[to].push_back(m-1);
}
int Maxflow(int s, int t){
int flow = 0;
for(;;){//有正反边一起跑 所以0的时候就不会再跑了
memset(a, 0, sizeof(a));
queue<int> q;
q.push(s);//从起点开始
a[s] = INF;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i=0; i<G[u].size(); i++){//所有和该点连着的边的序号
Edge &e = edges[G[u][i]];
if(!a[e.to] && e.cap > e.flow){
pre[e.to] = G[u][i];//前驱 用来往前回溯更新流量
a[e.to] = min(a[u], e.cap - e.flow);//往后递推直到终点
q.push(e.to);
}
}
if(a[t]) break;//找到了一条增广路
}
if(!a[t]) break;//如果最小残量已经为0了就没有增广路了
for(int i=t; i!=s; i=edges[pre[i]].from){
edges[pre[i]].flow += a[t];
edges[pre[i]^1].flow -= a[t];
}
flow += a[t];
}
return flow;
}
};
dinic算法(邻接表)(结合POJ1273)
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 1000000007
const int maxn = 2000 + 5;
using namespace std;
int dis[250];//距源点距离,分层图
int n,m;//n点数,M边数
struct Edge{
int from,to,cap;
Edge(){}
Edge(int f, int t, int c):from(f),to(t),cap(c){}
};
vector<Edge> edges;
vector<int> G[maxn];//存储相连的边的序号
void addedge(int u, int v, int cap)
{
edges.push_back(Edge(u,v,cap));
edges.push_back(Edge(v,u,0));
int sz = (int)edges.size();
G[u].push_back(sz-2);
G[v].push_back(sz-1);
}
int bfs(int s, int t){//起点到终点
queue<int> q;
memset(dis, -1, sizeof(dis));
dis[s] = 0;
q.push(s);
while(!q.empty()){
int u = q.front(); q.pop();
for(int i=0; i<(int)G[u].size(); i++){
Edge &e = edges[G[u][i]];
if(dis[e.to] == -1 && e.cap > 0){
dis[e.to] = dis[u] + 1;
q.push(e.to);
}
}
}
if(dis[t] > 0) return 1;
return 0;
}
int dinic(int x, int t, int flow){
if(x == t) return flow;
int a = 0;
for(int i=0; i<(int)G[x].size(); i++){
Edge &e = edges[G[x][i]];
if(dis[e.to] == dis[x] + 1 && e.cap > 0 && (a = dinic(e.to,t,min(flow,e.cap)))){
e.cap -= a;
edges[G[x][i]^1].cap += a;
return a;
}
}
return 0;
}
int main(){
while(scanf("%d%d",&m,&n) == 2){
for(int i=0; i<maxn; i++) G[i].clear();
edges.clear();
for(int i=0; i<m; i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
addedge(u, v, c);
addedge(v, u, 0);
}
int ans = 0;
while(bfs(1,n)){
ans += dinic(1,n,INF);
}
printf("%d\n",ans);
}
return 0;
}
最小割最大流定理:
参考:这篇博客
在不存在增广路的残量网络中,当BFS找不到(s,t)时,把已标号的点看作S,其他的即为T,则(S,T)即是最小割