有上下界的网络流学习笔记 – liu_runda

真次要是为了本身的回顾。

猜想讲读者可以纯熟地玩起落架。

有上下界的电网流的谷粒是”修补”,我们家经过一体未必F的初始流量来修补一体可加工的的流量。,最大/最小流量也可以从可加工的的修补,而不是基本的的。

可供选择的事物经用技术是源汇和顺从汇流(在周围流)的替换不计顺从吸光率可加工的流的求解,另外活跃的汇的上下界电网流都要用到这技术.

  1. 不抵抗的汇有上下界可加工的流(换句话说,在周围移动)

样板:一体电网,找到任一细流,依据每个边界附近的的移动必然的是>李。<=Hi,每个点必然的完成总流入量=总执行量(流量蜜饯)(这流的特点是在周围往复,无始无终).

这算法是有上下界电网流算法的根底,但愿我们家对算法受胎深化的懂,另外算法,依据,我努力在大空隙中解说该算法的思惟和特性。

可加工的流算法的谷粒是将一体不满流量蜜饯的初始流修补成完成流量蜜饯的流.

流量蜜饯,换句话说,每个点的总流入量=总执行量。

倘若有可加工的的连贯,这么必然完成每条边的流量都大于使相等的人流量的最高点.因而我们家可以令每条边的流量使相等的人流量最高点,获取初始流量。,于是建出这流的残量电网.(即:每条边的流量使相等的人这条边的流量最高点与流量最高点之差)这初始流未必完成流量蜜饯,依据终极的可加工的流必然是在这初始流的根底上增大了些许边的流量使得所短时间完成流量蜜饯.

依据,我们家思索一体不快的的残余流量。,例如使附加流与我们家的初始流合以完成C

倘若某个点在接受边流量使相等的人下界的初始流中完成流量蜜饯,这点也完成了附加流打中移动蜜饯。,

倘若一体点比初始流打中执行有更多的流入,则,这点在附加流打中执行量大于

倘若一体点在初始流中流入不足执行,x,依据,这点在附加流打中执行量不足

         可以以为附加流中任一从u到v的慢慢向前移动的一体流量代表将原图中u到v的流量增大1

x的数值可以详表x的接受边,更便利。,A[i]方针I在初始移动打中流入执行。,A[I]的正和负表现流入暗中的相干。,接下来,我们家运用一体[I]表现I在初始FLO打中流入和执行。

只是,DIIC算法可以找到运动宿SA的最大流。,不克不及在原电网上导演求一体这样地的不抵抗的汇且不满流量蜜饯的附加流.注意到附加流是在原电网上不满流量蜜饯的,这激起了我们家在原始电网超过添加些许边界附近的和点。,这些边和点用于达到预期的目的交通流的限度局限。

详细地,倘若一体点i在原电网上的附加流中必要完成流入量>执行量(初始流中流入量<执行量,A[i]<0),这么我们家必要给多的流入量找一体去处,因而我们家树立一体i动身移动的边界附近的= -a[i]。倘若[i]>0,换句话说,我们家必要在附加流>流入中执行。,我们家必要让更多的资产执行。,因而我们家树立关系i移动的边界附近的= a[i]

自然,我们家也必要有一体片刻来重行开端。,常一种办法可以得分我的边界附近的。,因而我们家新建一体蠢货源点ss和一体蠢货汇点tt(双写字母是为了和活跃的汇电网流打中源点s汇点t相区别).新建的得分i的边都从ss动身,从我的边得分一体点TT。或偏袒到TT。,任何偏袒都源自SS。,

TT边界附近的总流量的最高点必然的使相等的人UPP的最高点。,由于每个边都有两个正和负A[I]相当的奉献,依据,所短时间A[i]的和使相等的人0。,换句话说,不足0的总和的有无上权力或权威的=有无上权力或权威的O。

倘若我们家能找到完成新添加剂的流,则边是满的。,独创的流的分配是我们家必要的附加流。,“新加的边都满流”和”附加流合上初始流归因于流量均衡的流”是均势的约束条件).

这么我们家怎样才能找到任一盛产移动的边界附近的的新连贯呢?我们家可以看一眼条件,这样地的流必然的是我们家建筑的的图的SS TT最大流。,因而跑ss到tt的最大流那就够了.倘若最大流的规模使相等的人ss动身的接受边的流量最高点积和(此刻得分tt的边也必然满流,由于这两分配边的流量最高点积和相当).

结局,每条边在可加工的流打中流量=音量下界+附加流中它的流量(即跑完dinic然后所加反向边的权值).

法典(ZOJ2314 Reactor 葬)

#include
#include
#include
usingnamespace std;
constint maxn=300,maxm=100000;
struct edge{
  int to,next,w,num;
LST[MACM]int len=0,first[maxn],_first[maxn];
void addedge(int a,int b,int w,int 努姆)
  LST=num;
  LST=b;LSE].next=first[a];LSE].w=w;first[a]=len++;
  LST=num;
  LST=a;LSE].next=first[b];LSE].w=0最初的[B]=Le;
}
int vis[maxn],dis[maxn],q[maxn],head,tail,s,t,T;
bool bfs(){
  VIS[S]=++T;dis[s]=1;head=tail=0Q [尾]s;
  while(头)!=搭上)
    int x=q[head++];
    for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
      if(LST [Pt] W&&VIS[LST[Pt] to)!=T){
    Vist[LST[Pt] to ]DIS[LST[Pt] to ]=DIS[X]1Q [尾]LST [Pt]
      }
    }
  }
  if(V[t]=t),first,sizeof(一)
  return VIS[T]T;
}
int dfs(int x,int 林)
  if(x==t){
    return lim;
  }
  int flow=0,a;
  for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
    最初的[ X ]=pt;
    if(LST〔Pt〕W&&dis[lst[pt].to]==dis[x]+1(a=DFS(LST [Pt])。,min(LST[Pt]),lim-连贯)
      LST〔Pt〕Wa;1].w+=a;flow+=a;
      if(flow==lim)return flow;
    }
  }
  return flow;
}
int dinic(){
  int ans=0,x;
  while(BFS)
    while(x=dfs(s,0x7f7f7f7f))ans+=x;
  return ans;
}
int 低[注意斯],ANS[MACM]
int totflow[maxn],n,m;

void work(){
  memset(totflow,0,sizeof(totflow));
  memset(first,-1,sizeof(一)len=0;
  scanf("%d%d",&n,&m);
  int u,v,b;
  s=0;t=n+1;
  for(int i=1;i<=m;++i){
    scanf("%d%d%d%d",&u,&v,低[我],&b);
    addedge(u,v,b低[我],Ti流[U]=低[I];TutFLU[V]低[我]
  }
  int sum=0;
  for(int i=1;i<=n;++i){
    if(totflow[i]<0){
      addedge(i,t,-totflow[i],0);
    }else{
      sum+=totf低[我]
      addedge(s,i,totflow[i],0);
    }
  }
  if(第尼克)和)
    puts("YES");
    for(int i=1;i<=n;++i){
      for(int Pt=最初的[i];Pt!=-1;pt=LST [ Pt]。下一步)
    if(LST [Pt] num0||pt%2==0)continue;
    ANS[LST[Pt]·num ]=LST〔Pt〕W+低[LST[Pt]·num ]
      }
    }
    for(int i=1;i<=m;++i)printf("%d\n",ANS[I]
  }else puts("NO");
}
int main(){
  int 实验"%d",&试验)
  while(试验)){
    work();if(试验)用脚踩踏输入"\n");
  }
  return0;
}

  2. 活跃的汇有上下界可加工的流

样板:电网现时有一体。源点s发回点T,找到任一细流使得源点的总执行量使相等的人汇点的总流入量,另外点完成移动蜜饯。,同时每条边的流量完成最高点和下界限度局限.

源和汇不满流量蜜饯。,这使我们家很难做到这点。,因而我们家想办法把成绩转变成轻易处置的每个点都完成流量蜜饯的不抵抗的汇使适应.

为了使源汇完成流量蜜饯,我们家必要有边界附近的流入点S。,T.早已注意到S的执行使相等的人T的流入。,我们家就可以从汇点t向源点s连任一下界为0最高点为无量大的边,相当于把从源点s执行的流量再流背面.在这样地的图中套用上面的算法求出一体可加工的的在周围流,经过将T从汇点移除到源点S,一体可加工的的Act

在这一点上有一体小成绩:强劲的CON的终极可加工的流量是多少?

可以找到,在在周围流中必然的完成S执行的总流量。,猜想原始图中没边流入S。,S执行的移动是从T到S的无限的边流。,更确切地说s-t可加工的流的流量.因而我们家结局看一下t到s的无量边的流量(即dinic跑完然后反向边的权值)那就够了赚得原图中活跃的汇可加工的流的流量.

法典:这可加工的流算法在活跃的汇有上下界最大流/最小流中首府用到,你可以关照上面两个算法的法典。

3.活跃的汇有上下界最大流

样板:电网现时有一体。源点s发回点T,找到任一细流使得源点的总执行量使相等的人汇点的总流入量,另外点完成移动蜜饯。,同时每条边的流量完成最高点和下界限度局限.在这些先决条件的下规定总流量最高点.

率先套用上面的算法求出一体活跃的汇有上下界可加工的流.此刻的流未必最大.

接下来,在残余电网上运转S-最大流。

终极的最大流流量=可加工的流流量(即t到s的无量慢慢向前移动跑出的流量)+新增广出的s-t流量

成绩:当些许边不满TR的最高点时,它会提高某人的地位吗?

将不会.由于我们家一开端建的图执意把规模使相等的人流量最高点的流量拿出去然后的残量电网,形象的打中交通毫不。

法典:ZOJ 3229 Shoot The Bullet 东方文花帖 (由于ZoJ的评价可插件如同挂起了。,我不赚得我条件一直。,请深思熟虑。

#include
#include
#include
usingnamespace std;
constint maxn=2005,maxm=100005;
constint inf=0x7f7f7f7f;
struct edge{
  int to,next,w,num;
LST[MACM]int len=0,first[maxn],_first[maxn];
void addedge(int a,int b,int w,int 努姆)
  LST=num;
  LST=b;LSE].next=first[a];LSE].w=w;first[a]=len++;
  LST=num;
  LST=a;LSE].next=first[b];LSE].w=0最初的[B]=Le;
}
int q[maxn],vis[maxn],dis[maxn],T,s,t,head,tail,ss,tt;
bool bfs(){
  head=tail=0;VIS[S]=++TQ [尾]s;
  while(头)!=搭上)
    int x=q[head++];
    for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
      if(LST [Pt] W&&VIS[LST[Pt] to)!=T){
    Vist[LST[Pt] to ]DIS[LST[Pt] to ]=DIS[X]1Q [尾]LST [Pt]
      }
    }
  }
  if(V[t]=t),first,sizeof(一)
  return VIS[T]T;
}
int dfs(int x,int 林)
  if(x==t)return lim;
  int flow=0,a;
  for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
    最初的[ X ]=pt;
    if(LST〔Pt〕W&&dis[lst[pt].to]==dis[x]+1(a=DFS(LST [Pt])。,min(LST[Pt]),lim-连贯)
      LST〔Pt〕Wa;1].w+=a;flow+=a;
      if(flow==lim)return flow;
    }
  }
  return flow;
}
int dinic(){
  int ans=0,x;
  while(BFS)
    while(x=dfs(s,INF)x;
  return ans;
}
int totflow[maxn];
void Add(int a,int b,int lo,int hi,int 努姆)
  totflow[a]ToFLUT[B]lo;
  addedge(a,b,hi-lo,努姆)
}
int 低[注意斯],ANS[MACM]
int n,m,tot;
void bound_flow(){
  int sum=0;
  for(int i=s;i<=t;++i){
    if(totflow[i]<0){
      addedge(i,tt,-totflow[i],0);
    }else{
      sum+=totf低[我]
      addedge(ss,i,totflow[i],0);
    }
  }
  addedge(t,s,0x7f7f7f7f,0);
  int tmps=s,tmpt=t;
  sttt;
  if(第尼克)和)
    for(int Pt=最初的[SS];Pt!=-1;pt=LST [ Pt]。下一步)
      LST〔Pt〕WLST1].w=0;
    }
    for(int Pt=最初的[TT];Pt!=-1;pt=LST [ Pt]。下一步)
      LST〔Pt〕WLST1].w=0;
    }
    int flow0=LSE-1].w;
    LSE-1].w=LSE-2].w=0;
    sTMPStmpt;
    printf("%d\n",flow0+dinic());
    for(int i=1;i<=m;++i){
      for(int pt=first[i+n];pt!=-1;pt=LST [ Pt]。下一步)
    if(LST [Pt] num!=0){
      ANS[LST[Pt]·num ]=LST〔Pt〕W+低[LST[Pt]·num ]
    }
      }
    }
    for(int i=1;i<=tot;++i)printf("%d\n",ANS[I]
  }else{
    printf("-1\n");
  }
}

void work(){
  s=0;t=n+m+1;
  ss=n+m+2;tt=n+m+3;
  memset(first,-1,sizeof(一)len=0;
  memset(totflow,0,sizeof(totflow));
  int x,y;
  for(int i=1;i<=m;++i){
    scanf("%d",&x);
    添加(n)+i,t,x,inf,0);
  }
  int l,h;
  tot=0;
  for(int i=1;i<=n;++i){
    scanf("%d%d",&x,&y);
    添加(S),i,0,y,0);
    for(int j=1;j<=x;++j){
      ++tot;
      scanf("%d%d%d",&y,&l,&h);
      添加(i),n+y+1,l,h,低;l;
    }
  }
  bound_flow();printf("\n");
}
int main(){
  while(斯坎夫"%d%d",&n,&m)!=EOF任务
  return0;
}

4.活跃的汇有上下界最小流

样板:电网现时有一体。源点s发回点T,找到任一细流使得源点的总执行量使相等的人汇点的总流入量,另外点完成移动蜜饯。,同时每条边的流量完成最高点和下界限度局限.在这些先决条件的下规定最小总流量.

依然是先跑出一体活跃的汇可加工的流.这时候的流也未必是最小的.假设我们家能在残量电网上找到任一s-t的按某路线发送使得免除这条按某路线发送上的流量然后依然完成流量最高点,我们家就可以归因于一体更小的流.仿佛我们家并没什么算法可以”找到放量多的能去除流量的按某路线发送”

这时候必要我们家再懂一下dinic的反向边.反向边的流量提高某人的地位均势于正向边的的流量增加.因而我们家在残量电网上找出t到s的流就相当于减小了s到t的流,因而我们家在跑出可加工的流的残量电网上跑t-s最大流,用可加工的流的规模减去在这场合t-s最大流的规模执意最小流的规模.(t-s最大流真是放量减缩s-t关系的流).

问:它会增加交通到最高点的交通吗?

不,它与最大流量的最高点和最高点使相等。,我们家早已发生了初始流量从每一侧的交通与SIZ。,这些流量缺乏的我们家建出的图中.最顶点的使适应是减缩到接受边的流量使相等的人流量最高点,它将不会更小。

法典:bzoj2502 清扫雪路

#include
#include
#include
usingnamespace std;
constint maxn=205,maxm=100005;
struct edge{
  int to,next,w;
LST[MACM]int len=0,first[maxn],_first[maxn];
void addedge(int a,int b,int w){//PrdTf(添加 %d %d\n",a,b);
  LST=b;LSE].next=first[a];LSE].w=w;first[a]=len++;
  LST=a;LSE].next=first[b];LSE].w=0最初的[B]=Le;
}
int q[maxn],vis[maxn],dis[maxn],head,tail,s,t,T,ss,tt;
bool bfs(){
  head=tail=0;VIS[S]=++T;dis[s]=1Q [尾]s;
  while(头)!=搭上)
    int x=q[head++];
    for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
      if(LST [Pt] W&&VIS[LST[Pt] to)!=T){
    Vist[LST[Pt] to ]DIS[LST[Pt] to ]=DIS[X]1Q [尾]LST [Pt]
      }
    }
  }
  if(V[t]=t),first,sizeof(一)
  return VIS[T]T;
}
int dfs(int x,int 林)
  if(x==t)return lim;
  int flow=0,a;
  for(int Pt=最初的[X];Pt!=-1;pt=LST [ Pt]。下一步)
    最初的[ X ]=pt;
    if(LST〔Pt〕W&&dis[lst[pt].to]==dis[x]+1(a=DFS(LST [Pt])。,min(LST[Pt]),lim-连贯)
      LST〔Pt〕Wa;1].w+=a;flow+=a;
      if(flow==lim)return flow;
    }
  }
  return flow;
}
int dinic(){
  int ans=0,x;
  while(BFS){
    while(x=dfs(s,0x7f7f7f7f))ans+=x;
  }
  return ans;
}
int totflow[maxn];
void del(int x){
  for(int Pt=最初的[X];Pt!=-1;pt=lst[pt].next)LST〔Pt〕WLST1].w=0;
}
int main(){
  int 斯堪夫"%d",&n);
  int x,y;
  memset(first,-1,sizeof(一)
  for(int i=1;i<=n;++i){
    scanf("%d",&x);
    for(int j=1;j<=x;++j){
      scanf("%d",&y);
      totflow[i]--;totflow[y]++;
      addedge(i,y,0x7f7f7f7f);
    }
  }

  s=0;t=n+1;ss=n+2,tt=n+3;
  for(int i=1;i<=n;++i){
    addedge(s,i,0x7f7f7f7f);
    addedge(i,t,0x7f7f7f7f);
  }
  for(int i=1;i<=n;++i){
    if(totflow[i]<0){
      addedge(i,tt,-totflow[i]);
    }else{
      addedge(ss,i,totflow[i]);
    }
  }
  addedge(t,s,0x7f7f7f7f);
  int tmps=s,tmpt=t;
  sttt;
  dinic();
  int flow0=LSE-1].w;
  LSE-1].w=LSE-2].w=0;
  Del(SS)
  s甲状旁腺效能有力tmps;
  printf("%d\n",flow0-dinic());
  return0;
}

5.活跃的汇有上下界费流(待填坑,bzoj3876和Codeforces 708D,不外这两道题都可以诉讼费流的技术撤销上下界电网流)

发表评论

电子邮件地址不会被公开。 必填项已用*标注