• 有上下界的、有多组源汇的、网络流、费用流问题


    先默认读者有基础的网络流以及费用流的知识前置                                                                                                                                                                                                                                                                                                                                                   

    1.有上下界无源点汇点的可行流问题:

    在本文中指:

    原图中没有任何一个点可以凭空产生流量,亦没有任何一个点可以凭空消灭流量;

    存在边既有流量上界又有流量下界;

    求每条边流量的一组可行解;

    满足每个点的入流量等于出流量;

    由题意可见本题的图中有环,于是此类问题也被称作循环流;

    这里给出的解法是将本题转换为一道普通的有上界最大流问题;

    修改本题原图中每条边的流量下界为0,上界为原上界-原下界;

    视为该边现在已经拥有了等同于该边流量下界的基础流量了,

    然而,由于每条边在原图中的流量下界不同,导致他们现在的基础流量不同;

    于是如果再让现在图中每个点出入相等,则表面相等,实则不同;

    考虑当现在图中一条边i将x的流量汇入点a,实则汇入x+low[i]的流量(low[i]为i的下界),于是应当有额外一条low[i]的边连入a

    考虑当现在图中一条边i将x的流量运出点a,实则运出x+low[i]的流量(low[i]为i的下界),于是应当有额外一条low[i]的边自a连出

    由于这些额外的流量在现在图中看来是凭空产生的,所以所有连入原图的边应当自一个额外的源点出发,设为S`

    同理,所有连出原图的边应当去往一个额外的汇点,设为T`

    然后,跑S`到T`的最大流,希望他可以使附加的边满流;

    若附加边满流,则跑出了一组可行流,原图中每条边的可行流是他在现在图中对应边的流量加流量下界

    若不满流,则说明无论如何,原图中总会有边达不到下界,于是原图不存在可行流;

    注意:存在优化——即可以把所有同起点同终点的边等效为一条流量为加和的边,从S`到a的边的流量可以1:1抵消掉从a到T`的流量

    2.有上下界无源点汇点的最小费用流问题:

    在本文中指:

    在上个问题中的图上加权的费用流问题;

    这里给出的解法是直接在上题重构的图中,给每条边符合他来历的权值即可;

    由于一定附加边满流才有解,于是可以把附加边贡献的费用视为0上后单独算出加到答案中去;

    3.有上下界多个有限源汇点的可行流问题:

    在本文中指:

    在第一个问题的基础上,有些点必须消灭一定的流量,有些点必须产生一定的流量;

    对某些必须产生一定流量x的点,从S`连一条上限为x的附加边;

    对某些必须消灭一定流量x的点,向T`连一条上限为x的附加边;

    跑最大流,期望附加边满流;

    4.问题3的最小费用流版本:

    在问题3上附上费用,直接跑费用流即可

    5.有上下界一组无限流量源汇点的可行流问题:

    在本文中指:

    存在边既有流量上界又有流量下界;

    存在一个源点S可以随意产生流量,存在一个汇点T可以随便消灭流量

    求每条边流量的一组可行解;

    满足源汇点之外的每个点入流量等于出流量;

    可以看出S的流出等于T的流入;

    于是建一条从T到S的流量无限的边,本题的图就属于问题1了;

    有趣的是,边T->S的流量可以视作原图中S到T的总流量(因为连上此边后,S,T各自的出入相等)

    6.问题5的最小费用流版本:

    在问题5上附上费用,直接跑费用流即可

    7.问题5的最大流版本:

    先跑出问题5的一组可行流;

    然而这组可行流并不一定是最大流;

    发现一个性质,当我们采用增广路算法求解最大流时,并不会修改源点到汇点路径之外的边的流量大小;

    这意味着当我们第一次跑出问题5的一组可行解之后(跑这组可行解,即跑从S`到T`的最大流),

    在现在的图上直接跑S到T的最大流,

    就能保证

    1不会影响被视作原图中边流量下界的边的流量情况——他们依然是满流的;

    2图上连的T->S的INF边的退流过程,等价于有一条S->T的边在增广,于是他自动把第一次可行流的答案加入第二次跑出的最大流中;

    也就是说,这时跑出来的最大流可以被认为是满足上下界前提下的最大流;

    8.问题7的最小费用流版本:

    在问题7上附上费用,直接跑费用流即可

    题目:

    bzojP2502

    有上下界多个无限源点的费用流问题,好像保证了合法

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int INF=0x3f3f3f3f;
     6 int n,S,T,ansf,answ;
     7 struct ss{
     8     int next,to,f,v,cp;
     9 }e[30010];
    10 int first[210],num;
    11 int in[210];
    12 int que[100010],dis[210],vis[210],flow[210],pre[210],way[210];
    13 void bui_(int ,int ,int ,int );
    14 void build(int ,int ,int ,int );
    15 bool spfa();
    16 void EK();
    17 int main()
    18 {
    19     int i,j,k,l,o;
    20     scanf("%d",&n);
    21     S=n+1,T=S+1;
    22     for(i=1;i<=n;i++)
    23         bui_(S,i,INF,1);
    24     for(i=1;i<=n;i++){
    25         scanf("%d",&k),o=0;
    26         for(j=1;j<=k;j++){
    27             scanf("%d",&l);
    28             bui_(i,l,INF,0);
    29             in[l]++;o++;
    30         }
    31         bui_(i,T,o,0);
    32     }
    33     for(i=1;i<=n;i++)
    34         bui_(S,i,in[i],0);
    35     while(spfa())
    36         EK();
    37     printf("%d
    ",ansf);
    38     return 0;
    39 }
    40 void bui_(int f,int t,int fi,int vi){
    41     build(f,t,fi,vi),e[num].cp=num+1;
    42     build(t,f,0,-vi),e[num].cp=num-1;
    43 }
    44 void build(int f,int t,int fi,int vi){
    45     e[++num].next=first[f];
    46     e[num].to=t,e[num].f=fi,e[num].v=vi;
    47     first[f]=num;
    48 }
    49 bool spfa(){
    50     int i,h=0,t=1;
    51     for(i=1;i<=T;i++)vis[i]=0,dis[i]=0x3f3f3f3f;
    52     dis[S]=0,flow[S]=INF,que[t]=S;
    53     while(h<t){
    54         vis[que[++h]]=0;
    55         for(i=first[que[h]];i;i=e[i].next)
    56             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
    57                 dis[e[i].to]=dis[que[h]]+e[i].v;
    58                 pre[e[i].to]=que[h],way[e[i].to]=i;
    59                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
    60                 if(!vis[e[i].to]){
    61                     que[++t]=e[i].to;
    62                     vis[que[t]]=1;
    63                 }
    64             }
    65     }
    66     return dis[T]!=0x3f3f3f3f;
    67 }
    68 void EK(){
    69     int i;
    70     ansf+=(flow[T]*dis[T]);
    71     for(i=T;i;i=pre[i])
    72         if(way[i])
    73             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
    74 }
    Code1

    bzojP3876

    同上,

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int INF=1000000000;
     6 int n,S,T,ansf;
     7 struct ss{
     8     int to,next,f,v,cp;
     9 }e[26010];
    10 int first[1000],num;
    11 int in[1010];
    12 int que[1000010],vis[1010],dis[1010],pre[1010],flow[1010],way[1010];
    13 void bui_(int ,int ,int ,int );
    14 void build(int ,int ,int ,int );
    15 bool spfa();
    16 void EK();
    17 int main()
    18 {
    19     int i,j,k,b,t,su;
    20     scanf("%d",&n);
    21     S=n+1,T=S+1;
    22     bui_(S,1,INF,0);
    23     for(i=1;i<=n;i++){
    24         scanf("%d",&k);
    25         for(j=1;j<=k;j++){
    26             scanf("%d%d",&b,&t);
    27             bui_(i,b,INF,t);
    28             bui_(i,T,1,t);
    29             in[b]++,su+=t;
    30         }
    31     }
    32     for(i=1;i<=n;i++)
    33         if(in[i])
    34             bui_(S,i,in[i],0);
    35     bui_(S,1,INF,0);
    36     while(spfa())
    37         EK();
    38     printf("%d
    ",ansf);
    39 }
    40 void bui_(int f,int t,int fi,int vi){
    41     build(f,t,fi,vi),e[num].cp=num+1;
    42     build(t,f,0,-vi),e[num].cp=num-1;
    43 }
    44 void build(int f,int t,int fi,int vi){
    45     e[++num].next=first[f];
    46     e[num].to=t,e[num].f=fi,e[num].v=vi;
    47     first[f]=num;
    48 }
    49 bool spfa(){
    50     int i,h=0,t=1;
    51     memset(vis,0,sizeof(vis));
    52     memset(dis,0x3f,sizeof(dis));
    53     dis[S]=0,flow[S]=INF,que[t]=S;
    54     while(h<t){
    55         vis[que[++h]]=0;
    56         for(i=first[que[h]];i;i=e[i].next)
    57             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
    58                 dis[e[i].to]=dis[que[h]]+e[i].v;
    59                 pre[e[i].to]=que[h],way[e[i].to]=i;
    60                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
    61                 if(!vis[e[i].to]){
    62                     que[++t]=e[i].to;
    63                     vis[que[t]]=1;
    64                 }
    65             }
    66     }
    67     return dis[T]!=0x3f3f3f3f;
    68 }
    69 void EK(){
    70     int i;
    71     ansf+=(flow[T]*dis[T]);
    72     for(i=T;i;i=pre[i])
    73         if(way[i])
    74             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
    75 }
    Code2

    bzojP2055

    有上下界一个有上限源点的费用流问题,注意拆点限制流量

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int INF=0x3f3f3f3f;
     6 int n,m,S,T,ansf,answ;
     7 struct ss{
     8     int next,to,f,v,cp;
     9 }e[30010];
    10 int first[210],num;
    11 int que[100010],dis[210],vis[210],flow[210],pre[210],way[210];
    12 void bui_(int ,int ,int ,int );
    13 void build(int ,int ,int ,int );
    14 bool spfa();
    15 void EK();
    16 int main()
    17 {
    18     int i,j,k;
    19     scanf("%d%d",&n,&m);
    20     S=(n<<1)+2,T=S+1;
    21     bui_(S,S-1,m,0);
    22     for(i=1;i<=n;i++){
    23         scanf("%d",&j);
    24         bui_(i,T,j,0),bui_(S,i+n,j,0);
    25         bui_(S-1,i,INF,0);
    26     }
    27     for(i=1;i<n;i++)
    28         for(j=1;j<=n-i;j++){
    29             scanf("%d",&k);
    30             if(k!=-1)
    31                 bui_(i+n,i+j,INF,k);
    32         }
    33     while(spfa())
    34         EK();
    35     printf("%d
    ",ansf);
    36     return 0;
    37 }
    38 void bui_(int f,int t,int fi,int vi){
    39     build(f,t,fi,vi),e[num].cp=num+1;
    40     build(t,f,0,-vi),e[num].cp=num-1;
    41 }
    42 void build(int f,int t,int fi,int vi){
    43     e[++num].next=first[f];
    44     e[num].to=t,e[num].f=fi,e[num].v=vi;
    45     first[f]=num;
    46 }
    47 bool spfa(){
    48     int i,h=0,t=1;
    49     for(i=1;i<=T;i++)vis[i]=0,dis[i]=0x3f3f3f3f;
    50     dis[S]=0,flow[S]=INF,que[t]=S;
    51     while(h<t){
    52         vis[que[++h]]=0;
    53         for(i=first[que[h]];i;i=e[i].next)
    54             if(e[i].f&&dis[e[i].to]>dis[que[h]]+e[i].v){
    55                 dis[e[i].to]=dis[que[h]]+e[i].v;
    56                 pre[e[i].to]=que[h],way[e[i].to]=i;
    57                 flow[e[i].to]=min(e[i].f,flow[que[h]]);
    58                 if(!vis[e[i].to]){
    59                     que[++t]=e[i].to;
    60                     vis[que[t]]=1;
    61                 }
    62             }
    63     }
    64     return dis[T]!=0x3f3f3f3f;
    65 }
    66 void EK(){
    67     int i;
    68     ansf+=(flow[T]*dis[T]);
    69     for(i=T;i;i=pre[i])
    70         if(way[i])
    71             e[way[i]].f-=flow[T],e[e[way[i]].cp].f+=flow[T];
    72 }
    Code3

    bzojP3698

    有上下界一组源汇点的最大流问题;

      1 #include<cstdio>
      2 #include<cstring>
      3 using namespace std;
      4 const int INF=0x3f3f3f3f;
      5 int n,S,T;
      6 int in[210],out[210];
      7 struct ss{
      8     int next,to,f,cp;
      9 }e[100010];
     10 int first[210],num;
     11 int que[1000010],dep[210],cut[210];
     12 void bui_(int ,int ,int );
     13 void build(int ,int ,int );
     14 bool bfs();
     15 int dfs(int ,int );
     16 int main()
     17 {
     18     int i,j,k,add,ans=0;
     19     double inpu;
     20     scanf("%d",&n);
     21     S=(n<<1)+1,T=S+1;
     22     for(i=1;i<=n;i++)
     23         for(j=1;j<=n;j++){
     24             scanf("%lf",&inpu);
     25             if(i==n&&j==n)continue;
     26             if(i==n){
     27                 if(inpu>(int(inpu)))
     28                     bui_(j+n-1,T-2,1);
     29                 in[T-2]+=int(inpu),out[j+n-1]+=int(inpu);
     30                 continue;
     31             }
     32             if(j==n){
     33                 if(inpu>(int(inpu)))
     34                     bui_(S-2,i,1);
     35                 in[i]+=int(inpu),out[S-2]+=int(inpu);
     36                 continue;
     37             }
     38             if(inpu>(int(inpu)))
     39                 bui_(i,j+n-1,1);
     40             in[j+n-1]+=int(inpu),out[i]+=int(inpu);
     41         }
     42     bui_(T-2,S-2,INF);
     43     for(i=1;i<=T;i++){
     44         if(in[i]>out[i])bui_(S,i,in[i]-out[i]);
     45         if(out[i]>in[i])bui_(i,T,out[i]-in[i]),ans+=out[i]-in[i];
     46     }
     47     while(bfs())
     48         while(add=dfs(S,INF))
     49             ans-=add;
     50     if(ans){
     51         printf("No
    ");
     52         return 0;
     53     }
     54     S-=2,T-=2;
     55     while(bfs())
     56         while(add=dfs(S,INF))
     57             ans+=add;
     58     printf("%d
    ",ans*3);
     59     return 0;
     60 }
     61 void bui_(int f,int t,int fi){
     62     build(f,t,fi),e[num].cp=num+1;
     63     build(t,f,0),e[num].cp=num-1;
     64 }
     65 void build(int f,int t,int fi){
     66     e[++num].next=first[f];
     67     e[num].to=t,e[num].f=fi;
     68     first[f]=num;
     69 }
     70 bool bfs(){
     71     int i,h=0,t=1;
     72     memset(dep,0,sizeof(dep));
     73     for(i=1;i<=T;i++)cut[i]=first[i];
     74     que[t]=S,dep[S]=1;
     75     while(h<t){
     76         h++;
     77         for(i=first[que[h]];i;i=e[i].next)
     78             if(e[i].f&&!dep[e[i].to]){
     79                 que[++t]=e[i].to;
     80                 dep[que[t]]=dep[que[h]]+1;
     81             }
     82     }
     83     return dep[T];
     84 }
     85 int dfs(int now,int flow){
     86     int i,ret=0;
     87     if(now==T)
     88         return flow;
     89     for(i=cut[now];i;i=e[i].next)
     90         if(e[i].f&&dep[e[i].to]==dep[now]+1){
     91             ret=dfs(e[i].to,flow<e[i].f?flow:e[i].f);
     92             if(ret){
     93                 e[i].f-=ret;
     94                 e[e[i].cp].f+=ret;
     95                 cut[now]=i;
     96                 return ret;
     97             }
     98         }
     99     cut[now]=0;
    100     return 0;
    101 }
    Code4

    吐槽一句:

    bzoj什么也跑不过,luogu点数26w边数150w都跑得过

  • 相关阅读:
    iOS
    iOS
    iOS
    OpenGLES入门笔记四
    OpenGLES入门笔记三
    AVPlayer无法播放
    阿里云TTS重播报pointer being freed was not allocated错误
    [AVAssetWriter startWriting] Cannot call method when status is 1
    HTTP load failed (error code: -1009) / NSURLConnection finished with error
    在iPhone5上起始页卡着不动
  • 原文地址:https://www.cnblogs.com/nietzsche-oier/p/8185805.html
Copyright © 2020-2023  润新知