网络流之最大流

网络流之最大流

流函数三大性质:

1)容量限制:f(x,y) <= c(x,y)

2)斜对称:f(x,y)=-f(y,x)

3)流量守恒:x!=S,x!=T,Σf(u,x)=Σf(x,v)

c(x,y)=0说明该条边不在图中,同时f(x,y)<=0

最大流

EK算法 O(ve^2) 10^3--10^4 稀疏图

HDU 1532

# include <bits/stdc++.h>
using namespace std;

const int INF=0x7fffffff;
const int MAXN=250;
struct Edge{
   int to,w,next;
}edge[MAXN<<1];  //边要开两倍啊
int head[MAXN];
int tot;
void add(int u,int v,int w)
{
   edge[++tot].w+=w;  //有重边所以是+
   edge[tot].to=v;
   edge[tot].next=head[u];
   head[u]=tot;
   return ;
}
void init()
{
   tot=1;
   memset(head,-1,sizeof(head));
   memset(edge,0,sizeof(edge));
}

int N,M,S,T;
int vis[MAXN];
struct Pre{
   int u,e;
}pre[MAXN];
inline int bfs()
{
   memset(vis,0,sizeof(vis));
   memset(pre,-1,sizeof(pre));
   queue<int> q;
   q.push(S); vis[S]=1;
   while(!q.empty()){
       int u=q.front(); q.pop();
       for(int i=head[u];~i;i=edge[i].next){
           int v=edge[i].to;
           if(!vis[v]&&edge[i].w){
               pre[v].u=u; pre[v].e=i;
               if(v==T) return 1;
               vis[v]=1; q.push(v);
          }
      }
  }
   return 0;
}
inline int EK()
{
   int ans=0;
   while(bfs()){
       int mmin=INF;
       for(int i=T;i!=S;i=pre[i].u){
           mmin=min(mmin,edge[pre[i].e].w);
      }
       for(int i=T;i!=S;i=pre[i].u){
           edge[pre[i].e].w-=mmin;
           edge[pre[i].e^1].w+=mmin;
      }
       ans+=mmin;
  }
   return ans;
}
int main()
{
   while(~scanf("%d%d",&M,&N)){
       init();
       S=1,T=N;
       for(int i=1;i<=M;++i){
           int u,v,w; scanf("%d%d%d",&u,&v,&w);
           add(u,v,w); add(v,u,0);
      }
       printf("%d\n",EK());
  }
   return 0;
}

Dinic 算法 O(v^2e) 10^4--10^5 稠密图

求解二分图最大匹配的时间复杂度O(e sqrt(v))

# include <bits/stdc++.h>
using namespace std;

const int MAXN=2e4+1000;
const int INF=1e9;
struct Edge{
   int from,to,cap,flow;
   Edge(int u,int v,int w,int f):from(u),to(v),cap(w),flow(f){}
};
int N,M,S,T;
struct Dinic{
   vector<Edge> edges;
   vector<int> G[MAXN];
   int vis[MAXN],d[MAXN],cur[MAXN];  //代表从这条边下去一定搜不到
   void init()
  {
       for(int i=0;i<=N;++i) G[i].clear();
       edges.clear();
  }
   void add(int u,int v,int w)
  {
       edges.push_back(Edge(u,v,w,0));
       edges.push_back(Edge(v,u,0,0));
       int si=edges.size();
       G[u].push_back(si-2);
       G[v].push_back(si-1);
  }
   int Bfs()//分层图
  {
       memset(d,0,sizeof(d));
       memset(vis,0,sizeof(vis));
       d[S]=0; vis[S]=1;
       queue<int> Q;
       Q.push(S);
       while(!Q.empty()){
           int u=Q.front(); Q.pop();
           for(int i=0;i<G[u].size();++i){
               Edge &tmp=edges[G[u][i]];
               if(!vis[tmp.to]&&tmp.cap>tmp.flow){
                   vis[tmp.to]=1;
                   d[tmp.to]=d[u]+1;
                   Q.push(tmp.to);
              }
          }
      }
       return vis[T];
  }
   int Dfs(int node,int a)//a当前为止所有弧的最小残量
  {
       if(node==T||a==0) return a;
       int flow=0,f;
       for(int &i=cur[node];i<G[node].size();++i){//cur当前弧优化
           Edge &tmp=edges[G[node][i]];
           if(d[tmp.to]==d[node]+1&&(f=Dfs(tmp.to,min(a,tmp.cap-tmp.flow)))>0){
               flow+=f;
               tmp.flow+=f;
               edges[G[node][i]^1].flow-=f;
               a-=f;
               if(a==0) break;
          }
      }
       return flow;
  }
   int MaxFlow()
  {
       int flow=0;
       while(Bfs()){
           memset(cur,0,sizeof(cur));
           flow+=Dfs(S,INF);
      }
       return flow;
  }
};
Dinic dinic;
int main()
{
   while(~scanf("%d%d",&M,&N)){
       S=1,T=N;
       dinic.init();
       int u,v,w;
       for(int i=1;i<=M;++i){
           scanf("%d%d%d",&u,&v,&w);
           dinic.add(u,v,w);
      }
       int ans=0;
       ans=dinic.MaxFlow();
       printf("%d\n",ans);
  }
   return 0;
}

ISAP算法 O(v^2E)

# include <bits/stdc++.h>
using namespace std;

const int MAXN=1e4+100;
const int INF=0x7fffffff;
struct Edge{
   int from,to,cap,flow;
};
bool operator<(const Edge &a,const Edge &b){
   return a.from<b.from||(a.from==b.from&&a.to<b.to);
}
int N,M,S,T;
struct ISAP{
   vector<Edge> edges;
   vector<int> G[MAXN];
   int vis[MAXN],d[MAXN],cur[MAXN],p[MAXN],num[MAXN]; //p:增广路上的上一条弧 num:距离标号计数

   void add(int u,int v,int w){
       edges.push_back((Edge){u,v,w,0});
       edges.push_back((Edge){v,u,0,0});
       int si=edges.size();
       G[u].push_back(si-2);
       G[v].push_back(si-1);
  }
   int Bfs()  //分层图
  {
       memset(vis,0,sizeof(vis));
       memset(d,0,sizeof(d));
       queue<int> Q;
       Q.push(T); vis[T]=1;
       while(!Q.empty()){
           int v=Q.front(); Q.pop();
           for(int i=0;i<G[v].size();++i){
               Edge &e=edges[G[v][i]^1];
               if(!vis[e.from]&&e.cap>e.flow){
                   vis[e.from]=1;
                   d[e.from]=d[v]+1;
                   Q.push(e.from);
              }
          }
      }
       return vis[S];
  }
   void init()
  {
       for(int i=0;i<=N;++i) G[i].clear();
       edges.clear();
  }
   int Augment()
  {
       int x=T,a=INF;
       while(x!=S){
           Edge &e=edges[p[x]];
           a=min(a,e.cap-e.flow);
           x=edges[p[x]].from;
      }
       x=T;
       while(x!=S){
           edges[p[x]].flow+=a;
           edges[p[x]^1].flow-=a;
           x=edges[p[x]].from;
      }
       return a;
  }
   int MaxFlow()
  {
       Bfs();
       memset(num,0,sizeof(num));
       memset(cur,0,sizeof(cur));
       int flow=0;
       for(int i=0;i<=N;++i) num[d[i]]++;
       int x=S;
       while(d[S]<N){
           if(x==T){
               flow+=Augment();
               x=S;
          }
           int ok=0;
           for(int i=cur[x];i<G[x].size();++i){
               Edge &e=edges[G[x][i]];
               if(e.cap>e.flow&&d[x]==d[e.to]+1){
                   ok=1;
                   p[e.to]=G[x][i];
                   cur[x]=i;
                   x=e.to;
                   break;
              }
          }
           if(!ok){
               int m=N-1;
               for(int i=0;i<G[x].size();++i){
                   Edge &e=edges[G[x][i]];
                   if(e.cap>e.flow) m=min(m,d[e.to]);
              }
               if(--num[d[x]]==0) break;
               num[d[x]=m+1]++;
               cur[x]=0;
               if(x!=S) x=edges[p[x]].from;
          }
      }
       return flow;
  }
};
ISAP g;
int main()
{
   while(~scanf("%d%d",&M,&N)){
       g.init();
       S=1,T=N;
       int u,v,w;
       for(int i=1;i<=M;++i){
           scanf("%d%d%d",&u,&v,&w);
           g.add(u,v,w);
      }
       printf("%d\n",g.MaxFlow());
  }
   return 0;
}



posted @ 2022-02-26 23:38  fengzlj  阅读(29)  评论(0)    收藏  举报