网络流最大流(Edmonds-Karp&&)

Edmonds-Karp

根据定义,若一条从源点S到汇点T的路径上各点的剩余容量都大于0,则称这条路径为增广路。那么就可以通过不断寻找增广路来求出最大流。
具体做法就是通过bfs寻找从S到T的增广路径,并顺便计算出最小剩余容量minx,找到后路径上各点减去minx,答案(最大流)加上minx。
需要注意的是,因为是单纯的遍历所有剩余流量大于零的边,所以无法保证当前所选的边是否是最优,所以需要一种方法可以“后悔”,即撤回之前的决定,而这种“后悔”的方法就是退流,即在遍历时除了考虑当前遍历的边以外,还需要考虑每条边的反向边。
具体实现时,我们按照邻接表成对储存技巧,在存储边时下标从2开始,那么反向边和边之间可以通过xor 1来转换。

代码如下

#include<bits/stdc++.h>
using namespace std;
int n,m,S,T,linkk[205],t=1;
int q[505],head,tail;
int before[205],minx[205];
long long ans=0;
struct node{
  int y,v,n;
}e[405];
bool vis[205];
inline int read(){
  int NUM=0,f=1;
  char c=getchar();
  for(;c<'0'||c>'9';c=getchar())
  if(c=='-')f=-1;
  for(;c>='0'&&c<='9';c=getchar())
  NUM=(NUM<<1)+(NUM<<3)+c-48;
  return NUM*f;
}//快读
void insert(int xx,int yy,int zz){
  e[++t].y=yy;
  e[t].v=zz;
  e[t].n=linkk[xx];
  linkk[xx]=t;
  e[++t].y=xx;
  e[t].v=0;
  e[t].n=linkk[yy];
  linkk[yy]=t;
  return;
}//正反存边
void init(){
  n=read();m=read();S=read();T=read();
  for(int i=1;i<=n;++i){
    int x,y,z;
    x=read();y=read();z=read();
    insert(x,y,z);
  }
  return;
}
void Up(){
  int now=m;
  while(now!=S){
    int i=before[now];
    e[i].v-=minx[m];
    e[i^1].v+=minx[m];
    now=e[i^1].y;
  }
  ans+=minx[m];
  return;
}
bool BFS(){
  memset(vis,0,sizeof(vis));
  head=1;tail=0;
  q[++tail]=S;
  vis[S]=1;
  minx[S]=1e9;
  for(;head<=tail;++head){
    int x=q[head];
    for(int i=linkk[x];i;i=e[i].n){
      if(!e[i].v)continue;
      int y=e[i].y;
      if(vis[y])continue;
      vis[y]=1;
      minx[y]=min(minx[x],e[i].v);//更新最小剩余容量
      q[++tail]=y;
      before[y]=i;
      if(y==T)     return 1;//遍历到终点,找到一条路径
    }
  }
  return 0;
}
void work(){
  while(BFS())Up();
  cout<<ans;
  return;
}
int main(){
  init();
  work();
  return 0;
} 

Dinic

由于Edmonds-Karp每次可能遍历整个残量网络,但只找出一条增广路,明显有很大的优化空间,所以就有了dinic。
与EK只能往父亲反不同,dinic是基于分层图的DFS,一次可以求出多条增广路,同时加入若干剪枝,一般能够处理10^4~10^5的网络。
代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e9;
int n,m,linkk[1005],t=1;
int q[2005],head,tail;
int dis[2005];
long long ans=0;
struct node{
  int y,v,n;
}e[1000005];
inline int read(){
  int NUM=0,f=1;
  char c=getchar();
  for(;c<'0'||c>'9';c=getchar())
  if(c=='-')f=-1;
  for(;c>='0'&&c<='9';c=getchar())
  NUM=(NUM<<1)+(NUM<<3)+c-48;
  return NUM*f;
}
void insert(int xx,int yy,int zz){
  e[++t].y=yy;e[t].v=zz;e[t].n=linkk[xx];linkk[xx]=t;
  e[++t].y=xx;e[t].v=0;e[t].n=linkk[yy];linkk[yy]=t;
  return;
}
void init(){
  n=read();m=read();
  for(int i=1;i<=n;++i){
    int x,y,z;
    x=read();y=read();z=read();
    insert(x,y,z);
  }
  return;
}
int dinic(int x,int flow,int fa){
  if(x==m)return flow;
  int rest=flow,k;
  for(int i=linkk[x];i&&rest;i=e[i].n){
    int y=e[i].y;
    if(e[i].v&&dis[y]==dis[x]+1){
      k=dinic(y,min(e[i].v,rest));
      if(!k)dis[y]=0;
      e[i].v-=k;
      e[i^1].v+=k;
      rest-=k;
    }
  }
  return flow-rest;
}
bool BFS(){
  memset(dis,0,sizeof(dis));
  head=1;tail=0;
  q[++tail]=1;
  dis[1]=1;
  for(;head<=tail;++head){
    int x=q[head];
    for(int i=linkk[x];i;i=e[i].n){
      if(e[i].v&&!dis[e[i].y]){
        dis[e[i].y]=dis[x]+1;
        q[++tail]=e[i].y;
        if(e[i].y==m)      return 1;
      }
    }
  }
  return 0;
}
void work(){
  int flow=0; 
  while(BFS())
    while(flow=dinic(1,MAXN,0))
      ans+=flow;
  cout<<ans;
  return;
}
int main(){
  init();
  work();
  return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值