#include<cstdio>
#include<cstring>
using namespace std;
const int M=500000,N=60000;
const int INF = 0x3fffffff;
struct Edge{
int from,to,cap,next;
};
int n,m;//总的点数,包括源点和汇点
Edge edge[M];
int q[N];
int head[N],dep[N];//dep为距离编号
int gap[N];//gap[x]=y:说明残留网络中dep[i]==x的节点有y个
int cnt;
void addedge(int u,int v,int w){
edge[cnt].from=u;edge[cnt].to=v;edge[cnt].cap=w;edge[cnt].next=head[u];head[u]=cnt++;
edge[cnt].from=v;edge[cnt].to=u;edge[cnt].cap=0;edge[cnt].next=head[v];head[v]=cnt++;
}
struct SAP{
int sum;
int src,des;
void init(){
src = 0;
des = n+m+1;
cnt=0;sum=0;
memset(head,-1,sizeof(head));
}
void bfs(int start,int end){
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
memset(q,-1,sizeof(q));
gap[0]=1;
int front,rear;
front=rear=0;
dep[end]=0;
q[rear++]=end;
while(front!=rear){
int u=q[front++];
if(front==N)front=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].to;
if(dep[v]!=-1)continue;
q[rear++]=v;
if(rear==N)rear=0;
dep[v]=dep[u]+1;
++gap[dep[v]];
}
}
}
int Maxflow(){
int res=0;
bfs(src,des);
int cur[N],stack[N];
int top=0;
memcpy(cur,head,sizeof(head));
int u=src;
int i;
while(dep[src]<n){//如果src找不到一个可达点,则dep[src] = n + 1自动退出
if(u==des){//找到汇点
int temp=INF,inser=n;
for(int i=0;i<top;i++){//找从src点到des点的所有边中的最容量为temp,而那条边的编号为insert
if(temp>edge[stack[i]].cap){
temp=edge[stack[i]].cap;
inser=i;
}
}
for(int i=0;i<top;i++){//将正向边-temp,反向变+temp
edge[stack[i]].cap-=temp;
edge[stack[i]^1].cap+=temp;
}
res+=temp;//总的流量加temp
top=inser;//stack只保留从src到最小边insert“前向点”之间的边的信息,即insert边以后的边信息都不要
u=edge[stack[top]].from;////u为insert的”前向点“
}
for(i=cur[u];i!=-1;i=edge[i].next){////当没有断层,找出一个可达边
if(edge[i].cap!=0&&dep[u]==dep[edge[i].to]+1)break;
}
if(i!=-1)//找到这个可达边,只能走到dep[u]-1;
{
cur[u]=i;//优化下次找dep[u] - 1不用从头开始找了
stack[top++]=i;
u=edge[i].to;
}
else{//当没有找到深度为dep[u] - 1的可达边,那只能找深度更大的边
if(--gap[dep[u]]==0)break; //出现断层,无增广路;
int minn = n; //从头开始找出深度最小的可达边
for(i=head[u];i!=-1;i=edge[i].next){
if(edge[i].cap==0)continue;
if(minn>dep[edge[i].to]){
minn=dep[edge[i].to];
cur[u]=i;
}
}
dep[u]=minn+1;//更新深度
++gap[dep[u]];
if(u!=src)//如果u不是源点,还得回溯到dep[u] + 1(这里的dep[u]!=minn + 1)层,并将dep[u]层点全部修改变大。一直回溯到源点
u=edge[stack[--top]].from;
}
}
return sum-res;
}
};
SAP sap;
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
int w;
sap.init();
//...
printf("%d\n",sap.Maxflow());
}
return 0;
}
网络流最大流sap算法模板
最新推荐文章于 2021-11-16 16:18:59 发布