有上下界网络流
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了有上下界网络流相关的知识,希望对你有一定的参考价值。
bzoj3876:支线剧情
【模型】有源无汇
【题意】每个点至少到达一次,令经过的总边权最小,每次从1出发。
【构图】对于x-->y 流量下界为1,上界为inf,费用为w
然后直接从S到T跑一遍费用流。注意图中的1代表了下界。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 202020 5 #define inf 1000000000 6 using namespace std; 7 int n,m,edgenum; 8 int S,T,ans,tmp; 9 int next[N],head[N],vet[N],pri[N],cost[N],q[N],inq[N],dis[N]; 10 void add(int u,int v,int w,int c){ 11 edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;pri[edgenum]=w;cost[edgenum]=c; 12 edgenum++;vet[edgenum]=u;next[edgenum]=head[v];head[v]=edgenum;pri[edgenum]=0;cost[edgenum]=-c; 13 } 14 bool bfs() 15 { 16 int tou=1,tail=1;q[1]=T; 17 for(int i=0;i<=T;i++)dis[i]=inf; 18 for(int i=0;i<=T;i++)inq[i]=0; 19 dis[T]=0;inq[T]=1; 20 while(tou<=tail) 21 { 22 int u=q[tou%200005],e=head[u],ee; 23 inq[u]=0; 24 while(e>0) 25 { 26 int v=vet[e];if(e%2==1)ee=e+1;else ee=e-1; 27 if(dis[u]-cost[e]<dis[v]) 28 if(pri[ee]>0) 29 { 30 dis[v]=dis[u]-cost[e]; 31 if(inq[v]==0) 32 { 33 tail++; 34 q[tail%200005]=v;inq[v]=1; 35 } 36 } 37 e=next[e]; 38 } 39 tou++; 40 } 41 return (dis[S]!=inf); 42 } 43 int dfs(int u,int aug) 44 { 45 inq[u]=1; 46 if(u==T)return aug; 47 int e=head[u];int used=0,w; 48 while(e>0) 49 { 50 int v=vet[e],ee;if(e%2==1)ee=e+1;else ee=e-1; 51 if(pri[e]>0) 52 if(inq[v]==0) 53 if(dis[v]==dis[u]-cost[e]) 54 { 55 w=dfs(v,min(aug-used,pri[e])); 56 ans+=w*cost[e]; 57 used+=w;pri[e]-=w;pri[ee]+=w; 58 if(used==aug)return aug; 59 } 60 e=next[e]; 61 } 62 return used; 63 } 64 65 int main() 66 { 67 scanf("%d",&n); 68 S=0;T=n+1; 69 for(int i=1;i<=n;i++){ 70 scanf("%d",&m); 71 add(i,T,m,0); 72 add(i,1,inf,0); 73 for(int j=1;j<=m;j++){ 74 int b,t;scanf("%d%d",&b,&t); 75 add(i,b,inf,t); 76 add(S,b,1,t); 77 } 78 } 79 ans=0;tmp=0; 80 while(bfs()){ 81 inq[T]=1; 82 while(inq[T]){ 83 memset(inq,0,sizeof(inq)); 84 tmp+=dfs(S,inf); 85 } 86 } 87 printf("%d",ans); 88 }
bzoj3898:XWW的难题
【模型】无源无汇
【题意】每行前n-1个数之和等于该行最末一个,每列同理。a[n][n]始终为零。对每个数做取整操作(向上取整或向下),判断可行性并输出最大和为多少
【构图】新建S,T,SS,TT。如下图,跑出来的最大流为一边红色格子之积,ans*3即可。计算每个点的in,正值为SS流进的流,负值为流出到TT。
对于S-->行末尾格子,列尾格子到T,若其有+1空间(也就是小数部分不为零),则对其连边。
对于每一个(i,j),i-->j+n连边,其中权值1均为上界-下界的值,所有下界已经用SS,TT实现。
第一遍SS-->TT判断是否可行;
第二遍在残余网络上跑S-->T;
虽然我也不知道为什么可以这样
1 #include<cstdio> 2 #include<algorithm> 3 #define N 402020 4 #define mo 400000 5 #define inf 1000000000 6 using namespace std; 7 int S,T,s,t,tot,h[N],ans=0,q[N],SS,TT,edgenum; 8 int n,k,in[N],vet[N],head[N],pri[N],next[N],cost[N]; 9 double a[202][202]; 10 void add(int u,int v,int w){edgenum++;vet[edgenum]=v;next[edgenum]=head[u];head[u]=edgenum;pri[edgenum]=w;} 11 void ins(int u,int v,int w){add(u,v,w);add(v,u,0);} 12 void build(){ 13 for(int i=1;i<n;i++){ 14 if(a[i][n]!=(int)a[i][n])ins(S,i,1); 15 in[S]-=(int)a[i][n]; 16 in[i]+=(int)a[i][n]; 17 } 18 for(int i=1;i<n;i++){ 19 if(a[n][i]!=(int)a[n][i])ins(i+n,T,1); 20 in[T]+=(int)a[n][i]; 21 in[i+n]-=(int)a[n][i]; 22 } 23 for(int i=1;i<n;i++) 24 for(int j=1;j<n;j++){ 25 if(a[i][j]!=(int)a[i][j])ins(i,j+n,1); 26 in[i]-=(int)a[i][j]; 27 in[j+n]+=(int)a[i][j]; 28 } 29 for(int i=1;i<=TT;i++)if(in[i]>0){ 30 tot+=in[i];ins(SS,i,in[i]); 31 }else ins(i,TT,-in[i]); 32 } 33 int dfs(int u,int aug){ 34 if(u==t)return aug; 35 int used=0,w,e=head[u],ee; 36 while(e>0){ 37 int v=vet[e]; 38 if(h[v]==h[u]+1)if(pri[e]>0){ 39 if(e%2==1)ee=e+1;else ee=e-1; 40 w=dfs(v,min(aug-used,pri[e])); 41 used+=w;pri[e]-=w;pri[ee]+=w; 42 if(used==aug)return aug; 43 } 44 e=next[e]; 45 } 46 if(used<=0)h[u]=-1; 47 return used; 48 } 49 bool bfs(){ 50 for(int i=0;i<=TT;i++)h[i]=-1; 51 h[s]=0;int tou=1,tail=1;q[1]=s; 52 while(tou<=tail){ 53 int u=q[tou%mo],e=head[u]; 54 while(e>0){ 55 int v=vet[e]; 56 if(h[v]<0)if(pri[e]>0){ 57 h[v]=h[u]+1;tail++;q[tail%mo]=v; 58 } 59 e=next[e]; 60 } 61 tou++; 62 } 63 return h[t]!=-1; 64 } 65 66 void dinic(int S,int T){ 67 ans=0; 68 s=S;t=T; 69 while(bfs()){ans+=dfs(s,inf);} 70 } 71 int main() 72 { 73 scanf("%d",&n); 74 S=2*n+1;T=S+1;SS=T+1;TT=SS+1; 75 for(int i=1;i<=n;i++) 76 for(int j=1;j<=n;j++) 77 scanf("%lf",&a[i][j]); 78 build(); 79 ins(T,S,inf); 80 dinic(SS,TT); 81 if(tot!=ans){printf("No\\n");return 0;} 82 dinic(S,T); 83 printf("%d\\n",ans*3); 84 return 0; 85 }
以上是关于有上下界网络流的主要内容,如果未能解决你的问题,请参考以下文章