POJ 2396 有上下界的可行流
题意:
有一个n*m的方阵,里面的数字未知,但是我们知道如下约束条件:
每一行的数字的和
每一列的数字的和
某些格子有特殊的大小约束,用大于号,小于号和等于号表示
问:是否存在用正数填充这个方阵的方案,满足所有的约束,若有,输出之,否则输出IMPOSSIBLE。
题解:
参考的别人(darksword)的。
总结一下建图,忘了的时候还可以回顾~
求解一个有上下界的网络流的步骤:
1.首先进行构图,对于那么对流量没有限制的边,我们直接将容量赋值为原始的容量,而对于有流量要求的边,我们将容量减去下界并将其等价与无下界的边。最后就是添加一个附
加汇点和一个附加源点,从附加源点连向每个顶点的容量为以该点所有流入的下界流量总和,每个顶点流向附加汇点是该点流出的下界流量总和。
2.我们要添加一条从汇点到源点流量为INF的边,这条边的意义在于,能够使得源点会汇点满足成为流量平衡条件的普通节点。
(以下为有上下界的最小流求解步骤)
3.我们在以附加源点和附加汇点求一次最大流,如果所有的到附加汇点的边都满载,那么说明这个网络是存在满足所有下界的可行流的。因为去除了下界容量的图具备这个能力。但
是此时的可行流(从汇点流向源点的流量)并不一定是最小流,因为满足情况的可行流是不唯一的。
4.紧接着,我们在原图上从汇点向源点求一次最大流(此时要删除掉那条从汇点到源点的INF的边),此时便是一个缩流的过程,旨在试探图中是否还存在流量去替代汇点到源点的流量。这里计算出来的结果可能比我们已得到的可行流还要大,意思是说从汇点到源点有的是空间,因此也就不必连接那条INF的边了,整个网络的流量可以为0,网络中存在环流。
由于这里免不了会进行删边的操作,因此我们直接找到那条边,把流量赋值为0就可以了。
求解有上下界的最小流还有一种二分从汇点到原点的边的容量的方法~
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 }