有上下界网络流

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 } 
orzshenzhonghai

 

以上是关于有上下界网络流的主要内容,如果未能解决你的问题,请参考以下文章

[loj#115] 无源汇有上下界可行流 网络流

有上下界的网络流问题

BZOJ 2406 二分+有上下界的网络流判定

有上下界限制的网络流

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

有上下界网络流