最近学习了最大流虽然学的一般都是会简单的使用,一下是我用过的几个模板
模板一sap:
#include <bits/stdc++.h>
/*
用maze来存图
*/
typedef long long ll;
using namespace std;
const int MAXN=1100;
int maze[MAXN][MAXN];
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];
int sap(int start,int End,int nodenum) {
memset(cur,0,sizeof(cur));
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
int u=pre[start]=start,maxflow=0,aug=-1;
gap[0]=nodenum;
while(dis[start]<nodenum) {
loop:
for(int v=cur[u]; v<nodenum; v++)
if(maze[u][v]&&dis[u]==dis[v]+1) {
if(aug==-1||aug>maze[u][v])
aug=maze[u][v];
pre[v]=u;
u=cur[u]=v;
if(v==End) {
maxflow+=aug;
for(u=pre[u]; v!=start; v=u,u=pre[u]) {
maze[u][v]-=aug;
maze[v][u]+=aug;
}
aug=-1;
}
goto loop;
}
int mindis=nodenum-1;
for(int v=0; v<nodenum; v++)
if(maze[u][v]&&mindis>dis[v]) {
cur[u]=v;
mindis=dis[v];
}
if((--gap[dis[u]])==0) break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return maxflow;
}
模板二 ISAP+bfs 初始化 + 栈优化:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define MST(a,b) memset(a,b,sizeof(a))
typedef long long ll;
const ll mod=1e4;
const int L=26,maxn=2e3+10;
int n,m,k,T;
struct Edge {
int to,next,cap,flow;//cap想当与帽子
} edge[maxn];
int tol,head[maxn],gap[maxn],dep[maxn],S[maxn],cur[maxn];
void init() {
tol=0,MST(head,-1);
}
void addedge(int u,int v,int w,int rw=0) { //如果需要两边同时键边的话传入(u,v,w,w),因为用数组存的时候默认对边是0,;
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
edge[tol].flow=0;
head[u]=tol++;
edge[tol].to=u;
edge[tol].cap=rw;
edge[tol].next=head[v];
edge[tol].flow=0;
head[v]=tol++;
}
int Q[maxn];
void bfs(int st,int en) {
MST(dep,-1),MST(gap,0);
gap[0]=1;
int front=0,rear=0;
dep[en]=0,Q[rear++]=en;
while(front!=rear) {
int u=Q[front++];
for(int i=head[u]; i!=-1; i=edge[i].next) {
int v=edge[i].to;
if(dep[v]!=-1) continue;
Q[rear++]=v;
dep[v]=dep[u]+1;
gap[dep[v]]++;
}
}
}
int sap(int st,int en,int N) {
bfs(st,en);
memcpy(cur,head,sizeof(head));
int top=0,u=st,ans=0;
while(dep[st]<N) {
if(u==en) {
int Min=INF,inser;
for(int i=0; i<top; i++)
if(Min>edge[S[i]].cap-edge[S[i]].flow)
Min=edge[S[i]].cap-edge[S[i]].flow,inser=i;
for(int i=0; i<top; i++)
edge[S[i]].flow+=Min,edge[S[i]^1].flow-=Min;
ans+=Min,top=inser,u=edge[S[top]^1].to;
continue;
}
bool flag=false;
int v;
for(int i=cur[u]; i!=-1; i=edge[i].next) {
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) {
flag=true,cur[u]=i;
break;
}
}
if(flag) {
S[top++]=cur[u];
u=v;
continue;
}
int Min=N;
for(int i=head[u]; i!=-1; i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
Min=dep[edge[i].to],cur[u]=i;
gap[dep[u]]--;
if(!gap[dep[u]]) return ans;
dep[u]=Min+1,gap[dep[u]]++;
if(u!=st) u=edge[S[--top]^1].to;
}
return ans;
}
模板三 裸最大流:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=1100;
const int INF=0x3f3f3f3f;
int g[MAXN][MAXN];//原图的流量
int flow[MAXN][MAXN];//最后求得最大流的流量
int path[MAXN];
int a[MAXN];
int start,End,m;
int n;//顶点数,编号1~n
const int MAXM=1550;
int x[MAXM],y[MAXM];
int Max_Flow(){
queue<int >q;
memset(flow,0,sizeof(flow));
int maxflow=0;
while(1){
memset(a,0,sizeof(a));
a[start]=INF;
while(!q.empty())q.pop();
q.push(start);
while(!q.empty()){
int u=q.front();q.pop();
//if(u==End)break;
for(int v=1;v<=n;v++){
if(!a[v]&&flow[u][v]<g[u][v]){
path[v]=u;
a[v]=min(a[u],g[u][v]-flow[u][v]);
q.push(v);
}
}
}
if(a[End]==0) break;
for(int u=End;u!=start;u=path[u]){
flow[path[u]][u]+=a[End];
flow[u][path[u]]-=a[End];
}
maxflow+=a[End];
}
return maxflow;
}
int main(){
int t;
scanf("%d",&t);
int cas=1,cost;
while(t--){
scanf("%d %d",&n,&m);
memset(g,0,sizeof(g));
for(int i=0;i<m;i++){
scanf("%d %d",&x[i],&y[i]);
scanf("%d",&cost);
g[x[i]][y[i]]+=cost;
//maze[b][a]=cost;
}
int sum=0;
start=1;End=n;
sum=Max_Flow();
printf("Case %d: %d\n",cas++,sum);
}
return 0;
}
模板四 FF算法:(辣鸡算法)
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 205;
struct node {
int v, w, next;
} edge[maxn*maxn];
int no, n, m;
int head[maxn], pre[maxn], rec[maxn], flow[maxn];
stack<int> stk;
void init() {
no = 0;
memset(head, -1, sizeof head);
}
//静态邻接表存边
void add(int u, int v, int w) {
edge[no].v = v;
edge[no].w = w;
edge[no].next = head[u];
head[u] = no++;
edge[no].v = u;
edge[no].w = 0;
edge[no].next = head[v];
head[v] = no++;
}
int dfs(int S, int T) {
memset(pre, -1, sizeof pre);
while(!stk.empty()) stk.pop();
pre[S] = S;
flow[S] = inf;
stk.push(S);
while(!stk.empty()) { //用栈迭代替代dfs深搜
int top = stk.top();
stk.pop();
int k = head[top];
while(k != -1) {
if(pre[edge[k].v] == -1 && edge[k].w > 0) {
flow[edge[k].v] = min(flow[top], edge[k].w);
pre[edge[k].v] = top;
rec[edge[k].v] = k;
stk.push(edge[k].v);
}
k = edge[k].next;
}
if(pre[T] != -1) return flow[T];
}
return -1;
}
int FF(int s, int t) {
int ans = 0, add;
while((add = dfs(s, t)) != -1) { //直到找不到增广路
ans += add;
int k = t;
while(k != s) {
edge[rec[k]].w -= add;
edge[rec[k]^1].w += add;
k = pre[k];
}
}
return ans;
}
int main() {
ios::sync_with_stdio(0);
int u, v, w;
while(cin >> m >> n) {
init();
for(int i = 0; i < m; ++i) {
cin >> u >> v >> w;
add(u, v, w);
}
cout << FF(1, n) << endl;
}
return 0;
}
模板五 EK算法:(辣鸡算法)
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x7fffffff;
const int maxn = 205;
struct node {
int v, w, next;
} edge[maxn*maxn];
int no, n, m;
int head[maxn], pre[maxn], rec[maxn], flow[maxn];
queue<int> q;
void init() {
no = 0;
memset(head, -1, sizeof head);
}
//静态邻接表存边
void add(int u, int v, int w) {
edge[no].v = v;
edge[no].w = w;
edge[no].next = head[u];
head[u] = no++;
edge[no].v = u;
edge[no].w = 0;
edge[no].next = head[v];
head[v] = no++;
}
int dfs(int S, int T) {
memset(pre, -1, sizeof pre);
while(!q.empty()) q.pop();
pre[S] = S;
flow[S] = inf;
q.push(S);
while(!q.empty()) {
int top = q.front();
q.pop();
int k = head[top];
while(k != -1) {
if(pre[edge[k].v] == -1 && edge[k].w > 0) {
flow[edge[k].v] = min(flow[top], edge[k].w);
pre[edge[k].v] = top;
rec[edge[k].v] = k;
q.push(edge[k].v);
}
k = edge[k].next;
}
if(pre[T] != -1) return flow[T];
}
return -1;
}
int EK(int s, int t) {
int ans = 0, add;
while((add = dfs(s, t)) != -1) { //直到找不到增广路
ans += add;
int k = t;
while(k != s) {
edge[rec[k]].w -= add;
edge[rec[k]^1].w += add;
k = pre[k];
}
}
return ans;
}
int main() {
ios::sync_with_stdio(0);
int u, v, w;
while(cin >> m >> n) {
init();
for(int i = 0; i < m; ++i) {
cin >> u >> v >> w;
add(u, v, w);
}
cout << EK(1, n) << endl;
}
return 0;
}
模板六 Dinic:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10000 + 5;
const int MAXM = 100000 + 5;
const int INF = 1e9;
int n,m;
int s,t;//源点 汇点
int maxflow;//答案
struct Edge {
int next;
int to,flow;
} l[MAXM << 1];
int head[MAXN],cnt = 1;
int deep[MAXN],cur[MAXN];//deep记录bfs分层图每个点到源点的距离
queue <int> q;
inline void add(int x,int y,int z) {
cnt++;
l[cnt].next = head[x];
l[cnt].to = y;
l[cnt].flow = z;
head[x] = cnt;
return;
}
int min(int x,int y) {
return x < y ? x : y;
}
int dfs(int now,int t,int lim) {//分别是当前点,汇点,当前边上最小的流量
if(!lim || now == t) return lim;//终止条件
// cout<<"DEBUG: DFS HAS BEEN RUN!"<<endl;
int flow = 0;
int f;
for(int i = cur[now]; i; i = l[i].next) {//注意!当前弧优化
cur[now] = i;//记录一下榨取到哪里了
if(deep[l[i].to] == deep[now] + 1 //谁叫你是分层图
&& (f = dfs(l[i].to,t,min(lim,l[i].flow)))) {//如果还能找到增广路
flow += f;
lim -= f;
l[i].flow -= f;
l[i ^ 1].flow += f;//记得处理反向边
if(!lim) break;//没有残量就意味着不存在增广路
}
}
return flow;
}
bool bfs(int s,int t) {
for(int i = 1; i <= n; i++) {
cur[i] = head[i];//拷贝一份head,毕竟我们还要用head
deep[i] = 0x7f7f7f7f;
}
while(!q.empty()) q.pop();//清空队列 其实没有必要了
deep[s] = 0;
q.push(s);
while(!q.empty()) {
int tmp = q.front();
q.pop();
for(int i = head[tmp]; i; i = l[i].next) {
if(deep[l[i].to] > INF && l[i].flow) {//有流量就增广
//deep我赋的初值是0x7f7f7f7f 大于 INF = 1e9)
deep[l[i].to] = deep[tmp] + 1;
q.push(l[i].to);
}
}
}
if(deep[t] < INF) return true;
else return false;
}
void dinic(int s,int t) {
while(bfs(s,t)) {
maxflow += dfs(s,t,INF);
}
}
int main() {
cin>>n>>m;//点数边数
cin>>s>>t;
int x,y,z;
for(int i = 1; i <= m; i++) {
scanf("%d %d %d",&x,&y,&z);
add(x,y,z);
add(y,x,0);
}
dinic(s,t);
printf("%d",maxflow);
return 0;
}