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

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

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的边的退流过程,等价于有一条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\n",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\n",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\n",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\n");
 52         return 0;
 53     }
 54     S-=2,T-=2;
 55     while(bfs())
 56         while(add=dfs(S,INF))
 57             ans+=add;
 58     printf("%d\n",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 }

Code3

吐槽一句:

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

原文地址:https://www.cnblogs.com/nietzsche-oier/p/8185805.html

时间: 2024-08-25 13:23:58

有上下界的、有多组源汇的、网络流、费用流问题的相关文章

有源汇上下界可行流(POJ2396)

题意:给出一个n*m的矩阵的每行和及每列和,还有一些格子的限制,求一组合法方案. 源点向行,汇点向列,连一条上下界均为和的边. 对于某格的限制,从它所在行向所在列连其上下界的边. 求有源汇上下界可行流即可. 具体做法可以从汇点向源点连容量为正无穷的边,转成无源汇上下界可行流. 然后可以新建超级源汇,对于一条下界为l,上界为r的边(x,y),从超级源点向y,x向超级汇点连容量为l的边,x向y连容量为r-l的边. 如果那些容量为l的边没满流,则无解. #include <cstdio> #incl

上下界网络流小结

虽然网上已经有很详细的解释了,但是别人总结的终究是别人的. 1无源无汇上下界的可行流 首先明确定义:B[u, v]和C[u, v]表示边(u,v)的下界容量和上界容量,我们的问题是求一个每条边都具有上下界的可行流. 简单分析:由于每条边要满足下界容量,而且每个点要满足流量平衡,所以就需要对平时的网络流模型改造. 方法一:建立附加远点回电,S,T,对于边(u, v),连边S->v,容量B[u, v], 及u->T, 容量B[u, v], 然后对于本来的边u->v,容量改为C[u, v]-B

ZOJ 2314 带上下界的可行流

对于无源汇问题,方法有两种. 1 从边的角度来处理. 新建超级源汇, 对于每一条有下界的边,x->y, 建立有向边 超级源->y ,容量为x->y下界,建立有向边 x-> 超级汇,容量为x->y下界.建立有向边 x->y,容量为x->y的上界减下界. 2 从点的角度来处理. 新建超级源汇,对于每个点流进的下界和为 in, 流出此点的下界和为out.如果in > out. 建立有向边 超级源->i,容量为in-out.反之,建立有向边 i->超级汇

【BZOJ-3876】支线剧情 有上下界的网络流(有下界有源有汇最小费用最大流)

3876: [Ahoi2014]支线剧情 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 821  Solved: 502[Submit][Status][Discuss] Description [故事背景] 宅男JYY非常喜欢玩RPG游戏,比如仙剑,轩辕剑等等.不过JYY喜欢的并不是战斗场景,而是类似电视剧一般的充满恩怨情仇的剧情.这些游戏往往 都有很多的支线剧情,现在JYY想花费最少的时间看完所有的支线剧情. [问题描述] JYY现在所玩的R

sgu 176 上下界网络流最小可行流带输出方案

算法步骤: 1. 先将原图像最大可行流那样变换,唯一不同的是不加dst->src那条边来将它变成无源无汇的网络流图.直接跑一边超级源到超级汇的最大流. 2. 加上刚才没有加上的那条边p 3. 再跑一遍超级源汇之间的最大流,p的流量就是我们要求的最小可行流流量(等于其反向边的"容量") 收获: 1. 最大可行流和最小可行流,当我们把其残量网络求出来后,其流量就是dst->src的残量. 每条边在此时的流量 = 流量下界 + 转换后对应边的流量 1 #include <c

BZOJ-1305: [CQOI2009]dance跳舞(最大流 增加超级源汇+分裂点+二分 水题)

1305: [CQOI2009]dance跳舞 Time Limit: 5 Sec  Memory Limit: 162 MB Description 一次舞会有n个男孩和n个女孩.每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞.每个男孩都不会和同一个女孩跳两首(或更多)舞曲.有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”).每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞.给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲? Inpu

有上下界的网络流3-有源汇带上下界最小流SGU176

题目大意:有一个类似于工业加工生产的机器,起点为1终点为n,中间生产环节有货物加工数量限制,输入u v z c, 当c等于1时表示这个加工的环节必须对纽带上的货物全部加工(即上下界都为z),c等于0表示加工上界限制为z,下界为0,求节点1(起点)最少需要投放多少货物才能传送带正常工作. 解题思路:    1.直接 增设超级源点ss和超级汇点tt并连上附加边,对 当前图 求 无源汇带上下界可行流    2.将图的汇点sd连一条容量无限制的边到图的源点st,再求一遍 无源汇带上下界可行流    3.

有上下界的网络流2-有源汇带上下界网络流ZOJ3229

ZOJ3229题目大意:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝可以和C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能少于Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照:否则输出-1. 解题思路:        1.增设一源点st,汇点sd,st到第i天连一条上界为Di下界为0的边,每个女神到汇点连一条下界为Gi上界为正无穷的边,对于每一天,当天到第i个女孩连一条[Li,Ri]的边.        2.

有上下界的网络流1-无源汇带上下界网络流SGU194

今天开始啃网络流了.对于求解无源汇带上下界的网络流,我们可以这样建图:建图模型:         以前写的最大流默认的下界为0,而这里的下界却不为0,所以我们要进行再构造让每条边的下界为0,这样做是为了方便处理.对于每根管子有一个上界容量up和一个下界容量low,我们让这根管子的容量下界变为0,上界为up-low.可是这样做了的话流量就不守恒了,为了再次满足流量守恒,即每个节点"入流=出流",我们增设一个超级源点st和一个超级终点sd.我们开设一个数组du[]来记录每个节点的流量情况.