【网络流各种模板】

来源:互联网 发布:一键加群软件 编辑:程序博客网 时间:2024/05/16 16:23

EK 复杂度O(V*E*E)

#define N 204    int c[N][N];//边容量  int f[N][N];//边实际流量  int pre[N];//记录增广路径  int res[N];//残余网络  queue<int> qq;  void init(){      while(!qq.empty())qq.pop();      memset(c,0,sizeof(c));      memset(f,0,sizeof(f));  }  int EK(int s,int t){      int i,j;      int ans=0;      while(1){          memset(res,0,sizeof(res));          res[s] = MAX;//源点的残留网络要置为无限大!否则下面找增广路出错          pre[s] = -1;          qq.push(s);          //bfs找增广路径          while(!qq.empty()){              int x = qq.front();              qq.pop();              for(i=1;i<=t;i++){                  if(!res[i] && f[x][i] < c[x][i]){                      qq.push(i);                      pre[i] = x;                      res[i] = min(c[x][i] - f[x][i], res[x]);//这里类似dp,如果有增广路,那么res[t]就是增广路的最小权                  }              }          }          if(res[t]==0)break;//找不到增广路就退出          int k = t;          while(pre[k]!=-1){              f[pre[k]][k] += res[t];//正向边加上新的流量              f[k][pre[k]] -= res[t];//反向边要减去新的流量,反向边的作用是给程序一个后悔的机会              k = pre[k];          }          ans += res[t];      }      return ans;  }  

Dinic递归(推荐)


#define M 400    struct node {      int u, v, next, cap;  } edge[M*M];  int next[M], head[M], layer[M], Q[M * 2], mark[M];  int ecnt;  void init(){      ecnt= 0;      memset(head,-1,sizeof(head));  }  void add(int u, int v, int c) {      edge[ecnt].u = u;      edge[ecnt].v = v;      edge[ecnt].cap = c;      edge[ecnt].next = head[u];      head[u] = ecnt++;        edge[ecnt].u = v;      edge[ecnt].v = u;      edge[ecnt].cap = 0;      edge[ecnt].next = head[v];      head[v] = ecnt++;  }    bool BFS(int begin, int end) {      int i, l, h, k, y;      for (i = 0; i <= end; i++) layer[i] = -1;      layer[begin] = 0;      l = h = 0;      Q[l++] = begin;      while (h < l) {          k = Q[h++];          for (i = head[k]; i != -1; i = edge[i].next) {              y = edge[i].v;              if (edge[i].cap > 0 && layer[y] == -1) {                  layer[y] = layer[k] + 1;                  if (y == end)                      return true;                  Q[l++] = y;              }          }      }      return false;  }    int DFS(int x, int exp, int end) {      mark[x] = 1;      if (x == end)return exp;      int y, temp, i;      for (i = next[x]; i != -1; i = edge[i].next, next[x] = i) {          y = edge[i].v;          if (edge[i].cap > 0 && layer[y] == layer[x] + 1 && !mark[y]) {              if ((temp = (DFS(y, min(exp, edge[i].cap), end))) > 0) {                  edge[i].cap -= temp;//流完后正向流表示剩余流量                  edge[i^1].cap += temp;//流完后反向流表示正向流的流量                  return temp;              }          }      }      return 0;  }    int Dinic_flow(int begin, int end) {      int i, ans = 0, flow;      while (BFS(begin, end)) {          for (i = 0; i <= end; i++)next[i] = head[i];          while (true) {              for (i = 0; i <= end; i++) mark[i] = 0;              flow = DFS(begin, INT_MAX, end);              if (flow == 0)break;              ans += flow;          }      }      return ans;  }  


Dinic非递归 复杂度O(V^2*E)

#define N 20100#define sta que//静态邻接表int level[N];int p[N],p1[N];int ecnt;int que[N];int n,m;struct edge{    int v,next;    int c;}e[900000];void init(){    ecnt = 0;    memset(p,-1,sizeof(p));}void insert(int u,int v,int c,int w){    e[ecnt].v = v;    e[ecnt].c = c;    e[ecnt].next = p[u];    p[u] = ecnt++;    e[ecnt].v = u;    e[ecnt].c = w;    e[ecnt].next = p[v];    p[v] = ecnt++;}int Dinic(int st,int ed){    int ans = 0;    int i,u,v,c;    int head,rear,top;    while(1){//重建层次图        memset(level,0,sizeof(level));        head = rear = 0;        level[st]=1;        que[rear++]=st;        while(head<rear){            u = que[head++];            for(i=p[u];i!=-1;i=e[i].next){                v = e[i].v;                c = e[i].c;                if(c && level[v] == 0){                    level[v] = level[u]+1;                    que[rear++]=v;                }            }        }        if(level[ed] == 0){//无增广路            break;        }        memcpy(p1,p,sizeof(p1));        top = -1;        while(1){            if(top<0){                for(i=p1[st];i!=-1;i=e[i].next){                    v = e[i].v;                    c = e[i].c;                    if(c && p1[v] != -1 && level[v] == 2)break;                }                if(i>=0){                    sta[++top] = i;                    p1[st] = e[i].next;                } else break;            }            u = e[sta[top]].v;            if(u == ed){//找到一条增广路//计算流的可改进量,并记录离源点最远的可能会组成下一条增广路径的边                int dd = MAX,index = -1;                for(i=0;i<=top;i++){                    if(dd>e[sta[i]].c){                        dd = e[sta[i]].c;                        index = i;                    }                }                ans += dd;                //调整残余网络                for(i=0;i<=top;i++){                    //直接由上一残余网络计算当前残余网络 见导论P401                    e[sta[i]].c -= dd;                    e[sta[i]^1].c += dd;                }                //回溯到路径上某个可能继续增广的顶点,若该顶点也无法增广,则回溯到前一个顶点(1)                for(i=0;i<=top;i++){                    if(e[sta[i]].c==0){                        top = index-1;                        break;                    }                }            } else {                for(i=p1[u];i!=-1;i = e[i].next){                    v = e[i].v;                    c = e[i].c;                    if(c && p1[v]!=-1 && level[u]+1 == level[v])break;                }                if(i!=-1){                    sta[++top] = i;                    p1[u] = e[i].next;//若沿着边i找到了增广路,则p1会被从新初始化;否则断定从边i出发无法到达汇点,以后搜索增广路将不再考虑此边。估可将其忽略                } else {                    p1[u] = -1;                    top--;                }            }        }    }    return ans;}


SAP非递归  复杂度O(V*V*E)

#define N 440  #define M N*N  #define inf 1<<30int head[N];  struct Edge  {      int v,next,c;  }edge[M];  int ecnt;  void init(){      ecnt = 0;      memset(head,-1,sizeof(head));  }  void add(int u,int v,int w) {      edge[ecnt].v=v;      edge[ecnt].c=w;      edge[ecnt].next=head[u];      head[u]=ecnt++;      edge[ecnt].v=u;      edge[ecnt].c=0;      edge[ecnt].next=head[v];      head[v]=ecnt++;  }  int sap(int s,int t,int nodenum){ //源,汇,汇点编号(非点数)      int pre[N],cur[N],dis[N],gap[N];      int flow=0,aug=inf;      int u;      bool flag;      int i,j;      for(i=0;i<=nodenum;i++){              cur[i]=head[i];              gap[i]=dis[i]=0;      }      gap[s]=nodenum;      u=pre[s]=s;      while(dis[s]<nodenum){          flag=0;          for(j=cur[u];j!=-1;j=edge[j].next){                  int v=edge[j].v;                  if(edge[j].c>0 && dis[u]==dis[v]+1){                      flag=1;                      cur[u] = j;                      aug = min(aug,edge[j].c);                      pre[v]=u;                      u=v;                      if(u==t){                          flow+=aug;                          while(u!=s){                                u=pre[u];                              edge[cur[u]].c -= aug;    //边的正流不断减少                             edge[cur[u]^1].c += aug;  //反流增加                        }                          aug=inf;                      }                      break;                  }          }          if(flag)continue;          if(--gap[dis[u]] == 0)break;          for(dis[u] = nodenum, j=head[u]; j!=-1; j=edge[j].next){              int v=edge[j].v;              if(edge[j].c>0 && dis[v]<dis[u]){                  dis[u]=dis[v];                  cur[u]=j;              }          }          dis[u]++;          gap[dis[u]]++;          u=pre[u];      }      return flow;  }  

ISAP + GAP优化 复杂度O(V^2*E)

#define N 20010 #define M 500010int n,m;//n为点数 m为边数  int h[N];  int gap[N];  int p[N],ecnt;  int source,sink;  struct edge{      int v;      int next;//下一条边的编号      int val;//边权值  }e[M];    inline void init(){memset(p,-1,sizeof(p));ecnt=0;}     //有向  inline void add1(int from,int to,int val){      e[ecnt].v=to;      e[ecnt].val=val;      e[ecnt].next=p[from];      p[from]=ecnt++;         swap(from,to);         e[ecnt].v=to;      e[ecnt].val=0;      e[ecnt].next=p[from];      p[from]=ecnt++;  }     //无向  inline void add2(int from,int to,int val){      e[ecnt].v=to;      e[ecnt].val=val;      e[ecnt].next=p[from];      p[from]=ecnt++;        swap(from,to);         e[ecnt].v=to;      e[ecnt].val=val;      e[ecnt].next=p[from];      p[from]=ecnt++;  }       inline int dfs(int pos,int cost){      if (pos==sink){          return cost;      }      int j,minh=n-1,lv=cost,d;      for (j=p[pos];j!=-1;j=e[j].next){          int v=e[j].v,val=e[j].val;          if(val>0){              if (h[v]+1==h[pos]){                  if (lv<e[j].val) d=lv;                  else d=e[j].val;                     d=dfs(v,d);                  e[j].val-=d;                  e[j^1].val+=d;                  lv-=d;                  if (h[source]>=n) return cost-lv;                  if (lv==0) break;              }                 if (h[v]<minh)   minh=h[v];          }      }      if (lv==cost){          --gap[h[pos]];          if (gap[h[pos]]==0) h[source]=n;          h[pos]=minh+1;          ++gap[h[pos]];      }      return cost-lv;  }     int sap(int st,int ed){      source=st;      sink=ed;      int ans=0;      memset(gap,0,sizeof(gap));      memset(h,0,sizeof(h));      gap[st]=n;      while (h[st]<n){          ans+=dfs(st,INT_MAX);      }      return ans;  }