POJ 2396 有上下界的可行流

题意:

有一个n*m的方阵,里面的数字未知,但是我们知道如下约束条件:

每一行的数字的和

每一列的数字的和

某些格子有特殊的大小约束,用大于号,小于号和等于号表示

问:是否存在用正数填充这个方阵的方案,满足所有的约束,若有,输出之,否则输出IMPOSSIBLE。

 

题解:

参考的别人(darksword)的。

总结一下建图,忘了的时候还可以回顾~

 

求解一个有上下界的网络流的步骤:

1.首先进行构图,对于那么对流量没有限制的边,我们直接将容量赋值为原始的容量,而对于有流量要求的边,我们将容量减去下界并将其等价与无下界的边。最后就是添加一个附
加汇点和一个附加源点,从附加源点连向每个顶点的容量为以该点所有流入的下界流量总和,每个顶点流向附加汇点是该点流出的下界流量总和。


2.我们要添加一条从汇点到源点流量为INF的边,这条边的意义在于,能够使得源点会汇点满足成为流量平衡条件的普通节点。

(以下为有上下界的最小流求解步骤)
3.我们在以附加源点和附加汇点求一次最大流,如果所有的到附加汇点的边都满载,那么说明这个网络是存在满足所有下界的可行流的。因为去除了下界容量的图具备这个能力。但
 是此时的可行流(从汇点流向源点的流量)并不一定是最小流,因为满足情况的可行流是不唯一的。


4.紧接着,我们在原图上从汇点向源点求一次最大流(此时要删除掉那条从汇点到源点的INF的边),此时便是一个缩流的过程,旨在试探图中是否还存在流量去替代汇点到源点的流量。这里计算出来的结果可能比我们已得到的可行流还要大,意思是说从汇点到源点有的是空间,因此也就不必连接那条INF的边了,整个网络的流量可以为0,网络中存在环流。

 

由于这里免不了会进行删边的操作,因此我们直接找到那条边,把流量赋值为0就可以了。

 

求解有上下界的最小流还有一种二分从汇点到原点的边的容量的方法~

 

View Code
  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdlib>
  5 
  6 #define N 400
  7 #define INF 1000000000
  8 
  9 using namespace std;
 10 
 11 int cap[N][N],up[N][N],down[N][N],flow[N][N],in[N],out[N];
 12 int q[N*100],layer[N];
 13 int n,m,T,S,TT,SS,sum,cas;
 14 
 15 inline void read()
 16 {
 17     memset(down,0,sizeof down);
 18     memset(flow,0,sizeof flow);
 19     memset(cap,0,sizeof cap);
 20     memset(in,0,sizeof in);
 21     memset(out,0,sizeof out);
 22     memset(up,0,sizeof up);
 23     scanf("%d%d",&n,&m);
 24     for(int i=1;i<=n;i++)
 25         for(int j=1;j<=m;j++)
 26             up[i][j+n]=INF;
 27     S=0; T=n+m+1;
 28     for(int i=1,a;i<=n;i++)
 29     {
 30         scanf("%d",&a);
 31         up[S][i]=down[S][i]=a;
 32     }
 33     for(int i=1,a;i<=m;i++)
 34     {
 35         scanf("%d",&a);
 36         up[i+n][T]=down[i+n][T]=a;
 37     }
 38     int qu; char str[4]; scanf("%d",&qu);
 39     for(int i=1,a,b,c;i<=qu;i++)
 40     {
 41         scanf("%d%d%s%d",&a,&b,str,&c);
 42         if(a==0&&b==0)
 43         {
 44             if(str[0]=='=')
 45             { 
 46                 for(int j=1;j<=n;j++)
 47                     for(int k=1;k<=m;k++)
 48                     {
 49                         down[j][k+n]=c;
 50                         up[j][k+n]=c;
 51                     }
 52             }
 53             else if(str[0]=='>')
 54             {
 55                 for(int j=1;j<=n;j++)
 56                     for(int k=1;k<=m;k++)
 57                         down[j][k+n]=max(c+1,down[j][k+n]);
 58             }
 59             else
 60             {
 61                 for(int j=1;j<=n;j++)
 62                     for(int k=1;k<=m;k++)
 63                         up[j][k+n]=min(c-1,up[j][k+n]);
 64             }
 65         }
 66         else if(a==0&&b!=0)
 67         {
 68             if(str[0]=='=')
 69             {
 70                 for(int j=1;j<=n;j++)
 71                 {
 72                     down[j][b+n]=c;
 73                     up[j][b+n]=c;
 74                 }
 75             }
 76             else if(str[0]=='>')
 77             {
 78                 for(int j=1;j<=n;j++)
 79                     down[j][b+n]=max(c+1,down[j][b+n]);
 80             }
 81             else
 82             {
 83                 for(int j=1;j<=n;j++)
 84                     up[j][b+n]=min(c-1,up[j][b+n]);
 85             }
 86         }
 87         else if(b==0&&a!=0)
 88         {
 89             if(str[0]=='=')
 90             {
 91                 for(int j=1;j<=m;j++)
 92                 {
 93                     down[a][j+n]=c;
 94                     up[a][j+n]=c;
 95                 }
 96             }
 97             else if(str[0]=='>')
 98             {
 99                 for(int j=1;j<=m;j++)
100                     down[a][j+n]=max(c+1,down[a][j+n]);
101             }
102             else
103             {
104                 for(int j=1;j<=m;j++)
105                     up[a][j+n]=min(c-1,up[a][j+n]);
106             }
107         }
108         else if(a!=0&&b!=0)
109         {
110             if(str[0]=='=')
111             {
112                 down[a][b+n]=c;
113                 up[a][b+n]=c;
114             }
115             else if(str[0]=='>') down[a][b+n]=max(c+1,down[a][b+n]);
116             else up[a][b+n]=min(c-1,up[a][b+n]);
117         }
118     }
119 }
120 
121 inline bool bfs(int st,int ed)
122 {
123     memset(layer,-1,sizeof layer);
124     int h=1,t=2,sta;
125     q[1]=st; layer[st]=0;
126     while(h<t)
127     {
128         sta=q[h++];
129         for(int i=0;i<=ed;i++)
130             if(cap[sta][i]>0&&layer[i]<0)
131             {
132                 layer[i]=layer[sta]+1;
133                 q[t++]=i;
134             }
135     }
136     return layer[ed]!=-1;
137 }
138 
139 inline int find(int u,int t,int cur_flow)
140 {
141     if(u==t) return cur_flow;
142     int res=0,tmp;
143     for(int i=0;i<=t&&res<cur_flow;i++)
144         if(cap[u][i]>0&&layer[i]==layer[u]+1)
145         {
146             tmp=find(i,t,min(cur_flow-res,cap[u][i]));
147             cap[u][i]-=tmp; cap[i][u]+=tmp; 
148             flow[u][i]+=tmp; flow[i][u]-=tmp;
149             res+=tmp;
150         }
151     if(!res) layer[u]=-1;
152     return res;
153 }
154 
155 inline int dinic(int s,int t)
156 {
157     int ans=0;
158     while(bfs(s,t)) ans+=find(s,t,INF);
159     return ans;
160 }
161 
162 inline void go()
163 {
164     sum=0;
165     SS=T+1; TT=SS+1;
166     for(int i=0;i<=T;i++)
167         for(int j=0;j<=T;j++)
168         {
169             cap[i][j]=up[i][j]-down[i][j];
170             in[j]+=down[i][j];
171             out[i]+=down[i][j];
172             sum+=down[i][j];
173         }
174     for(int i=0;i<=T;i++)
175     {
176         cap[SS][i]=in[i];
177         cap[i][TT]=out[i];
178     }
179     cap[T][S]=INF;
180     int ans=dinic(SS,TT);
181     if(ans!=sum)
182     {
183         printf("IMPOSSIBLE\n");
184         return;
185     }
186     cap[T][S]=cap[S][T]=0;
187     ans=dinic(S,T);
188     for(int i=1;i<=n;i++)
189     {
190         printf("%d",flow[i][1+n]+down[i][1+n]);
191         for(int j=2;j<=m;j++)
192             printf(" %d",flow[i][j+n]+down[i][j+n]);
193         puts("");
194     }
195     puts("");
196 }
197 
198 int main()
199 {
200     scanf("%d",&cas);
201     while(cas--) read(),go();
202     return 0;
203 }

 

posted @ 2013-01-05 23:32  proverbs  阅读(1264)  评论(0编辑  收藏  举报