网络流我习惯采用EK算法
思想:
每次从残留网络找出一条增广路,并且沿着这条路增广即可,直至没有增广路
关于网络流的用处:
网络流就像水流一样,求最大的水流速率,很多问题可以转化为网络流模型来解决
- 二分图匹配( 最少边覆盖)
网络流的做题经验:
求最大消耗量:将产生值的连接到源点,消耗值的连接到汇点
顶点上有最大容量限制: 插点即可
边上有最小容量限制:(先放一放)假设u到v的最小容量限制为b(e), 那么新增S‘,T’ 让 u到T‘ 流量为b(e),S’到v的流量为b(e) 然后令u到v的容量为c(e)-b(e) 。不过要在S与s,T与t连接之前,先检查S到T的最大容量是否为Sum(e)(让 v到s容量为b(e),)
代码:
#include<queue>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn=120;
const int inf=0x3f3f3f3f;
struct edge{
int cap,rev,to;//储存 容量、邻接点、反向边
edge(){};
edge(int to,int cap,int rev){this->to=to,this->cap=cap,this->rev=rev;}
};
class EK{
public:
vector<edge> adja[maxn];
int prevv[maxn],top;
int preve[maxn];
void init(int n)
{
for(int i=0;i<n;++i) adja[i].clear();
top=n;
}
void bfs(int s,int t)
{
memset(prevv,-1,sizeof(prevv));
queue<int> mmp;
mmp.push(s);
prevv[s]=s;
while(!mmp.empty()){
int u=mmp.front();
mmp.pop();
for(int i=0;i<adja[u].size();++i){
edge& e=adja[u][i];
if(prevv[e.to]==-1&&e.cap>0)
{
prevv[e.to]=u;
preve[e.to]=i;
mmp.push(e.to);
}
}
}
}
void addEdge(int u,int v,int f)
{
adja[u].push_back(edge(v,f,adja[v].size()));
adja[v].push_back(edge(u,0,adja[u].size()-1));
}
int maxFlow(int s,int t)
{
int flow=0;
for(;;)
{
bfs(s,t);
if(prevv[t]==-1)
return flow;
else
{
int minn=inf;
for(int last=t;prevv[last]!=last;last=prevv[last]){
minn=min(minn,adja[prevv[last]][preve[last]].cap);
}
flow+=minn;
for(int last=t;prevv[last]!=last;last=prevv[last]){
edge& e=adja[prevv[last]][preve[last]];
e.cap-=minn;
adja[last][e.rev].cap+=minn;
}
}
}
}
};
EK kit;
int main()
{
}
我bing神的模板贼快 ISAP+BSF+栈优化
const int MAXN=100010;//点数的最大值
const int MAXM=400010;//边数的最大值
const int INF=0x3f3f3f3f;
const int inf=0x3f3f3f3f;
struct Edge
{
int to,next,cap,flow;
} edge[MAXM];
class ISAP
{
//输入参数:起点、终点、点的总数
//点的编号没有影响,只输入点的总数
public:
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void init()
{
tol=0;
mset(head,-1);
}
void addEdge(int u,int v,int w,int rw=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 start,int end)
{
mset(dep,-1),mset(gap,0);
gap[0]=1;
int front=0,rear=0;
dep[end]=0;
Q[rear++]=end;
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 S[MAXN];
int sap(int start,int end,int N)//只输入源点和汇点的编号 和顶点个数
{
BFS(start,end);
memcpy(cur,head,sizeof(head));
int top=0,u=start,ans=0;
while(dep[start]<N)
{
if(u==end)
{
int Min=INF;
int 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!=start) u=edge[S[--top]^1].to;
}
return ans;
}
};