POJ2396 Budget(有源汇流量有上下界网络的可行流)
题目大概给一个有n×m个单元的矩阵,各单元是一个非负整数,已知其每行每列所有单元的和,还有几个约束条件描述一些单元是大于小于还是等于某个数,问矩阵可以是怎样的。
经典的流量有上下界网络流问题。
- 把行、列看成点,各单元看成边
- 源点向各行连容量下界0上界该行和的边,各列向汇点连容量下界0上界该列和的边
- 对于各单元,其对应行列表示的边间连下界上界和约束条件对应的边
这样就是求解这个网络的可行流,可以通过汇点向源点连容量INF的边,使各个顶点都满足平衡条件,这样转化成无源汇有上下界网络流来求解。
最后就是再转化一下求解无源汇有上下界网络流了,见ZOJ2314。
要注意的是条件是负数的时候,要的是非负整数解,有些就直接是IMPOSSIBLE,而对于>-100这种情况是可以的,不过因为网络流的容量不能为负,这时把-100设置成0即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 #define INF (1<<30) 7 #define MAXN 444 8 #define MAXM 444*888 9 10 struct Edge{ 11 int v,cap,flow,next; 12 }edge[MAXM]; 13 int vs,vt,NE,NV; 14 int head[MAXN]; 15 16 void addEdge(int u,int v,int cap){ 17 edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0; 18 edge[NE].next=head[u]; head[u]=NE++; 19 edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0; 20 edge[NE].next=head[v]; head[v]=NE++; 21 } 22 23 int level[MAXN]; 24 int gap[MAXN]; 25 void bfs(){ 26 memset(level,-1,sizeof(level)); 27 memset(gap,0,sizeof(gap)); 28 level[vt]=0; 29 gap[level[vt]]++; 30 queue<int> que; 31 que.push(vt); 32 while(!que.empty()){ 33 int u=que.front(); que.pop(); 34 for(int i=head[u]; i!=-1; i=edge[i].next){ 35 int v=edge[i].v; 36 if(level[v]!=-1) continue; 37 level[v]=level[u]+1; 38 gap[level[v]]++; 39 que.push(v); 40 } 41 } 42 } 43 44 int pre[MAXN]; 45 int cur[MAXN]; 46 int ISAP(){ 47 bfs(); 48 memset(pre,-1,sizeof(pre)); 49 memcpy(cur,head,sizeof(head)); 50 int u=pre[vs]=vs,flow=0,aug=INF; 51 gap[0]=NV; 52 while(level[vs]<NV){ 53 bool flag=false; 54 for(int &i=cur[u]; i!=-1; i=edge[i].next){ 55 int v=edge[i].v; 56 if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){ 57 flag=true; 58 pre[v]=u; 59 u=v; 60 //aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap)); 61 aug=min(aug,edge[i].cap-edge[i].flow); 62 if(v==vt){ 63 flow+=aug; 64 for(u=pre[v]; v!=vs; v=u,u=pre[u]){ 65 edge[cur[u]].flow+=aug; 66 edge[cur[u]^1].flow-=aug; 67 } 68 //aug=-1; 69 aug=INF; 70 } 71 break; 72 } 73 } 74 if(flag) continue; 75 int minlevel=NV; 76 for(int i=head[u]; i!=-1; i=edge[i].next){ 77 int v=edge[i].v; 78 if(edge[i].cap!=edge[i].flow && level[v]<minlevel){ 79 minlevel=level[v]; 80 cur[u]=i; 81 } 82 } 83 if(--gap[level[u]]==0) break; 84 level[u]=minlevel+1; 85 gap[level[u]]++; 86 u=pre[u]; 87 } 88 return flow; 89 } 90 int d[MAXN]; 91 int low[MAXN][MAXN],up[MAXN][MAXN]; 92 int main(){ 93 int t,n,m,a,b,c; 94 char ch; 95 scanf("%d",&t); 96 while(t--){ 97 scanf("%d%d",&n,&m); 98 memset(d,0,sizeof(d)); 99 int S=0,T=n+m+1; 100 vs=T+1; vt=vs+1; NV=vt+1; NE=0; 101 memset(head,-1,sizeof(head)); 102 addEdge(T,S,INF); 103 bool flag=0; 104 for(int i=1; i<=n; ++i){ 105 scanf("%d",&a); 106 d[i]-=a; 107 if(a<0) flag=1; 108 } 109 for(int i=1; i<=m; ++i){ 110 scanf("%d",&a); 111 d[i+n]+=a; 112 if(a<0) flag=1; 113 } 114 for(int i=1; i<=n; ++i){ 115 for(int j=1; j<=m; ++j){ 116 low[i][j]=0; up[i][j]=INF; 117 } 118 } 119 int k; 120 scanf("%d",&k); 121 while(k--){ 122 scanf("%d%d",&a,&b); scanf(" %c",&ch); scanf("%d",&c); 123 if(ch=='>') ++c; 124 else if(ch=='<') --c; 125 if(ch=='<' && c<0) flag=1; 126 if(c<0) c=0; 127 if(a==0 && b==0){ 128 for(int i=1; i<=n; ++i){ 129 for(int j=1; j<=m; ++j){ 130 if(ch=='=') low[i][j]=up[i][j]=c; 131 else if(ch=='>') low[i][j]=c; 132 else up[i][j]=c; 133 } 134 } 135 }else if(a==0){ 136 for(int i=1; i<=n; ++i){ 137 if(ch=='=') low[i][b]=up[i][b]=c; 138 else if(ch=='>') low[i][b]=c; 139 else up[i][b]=c; 140 } 141 }else if(b==0){ 142 for(int i=1; i<=m; ++i){ 143 if(ch=='=') low[a][i]=up[a][i]=c; 144 else if(ch=='>') low[a][i]=c; 145 else up[a][i]=c; 146 } 147 }else{ 148 if(ch=='=') low[a][b]=up[a][b]=c; 149 else if(ch=='>') low[a][b]=c; 150 else up[a][b]=c; 151 } 152 } 153 for(int i=1; i<=n; ++i){ 154 for(int j=1; j<=m; ++j){ 155 addEdge(i,j+n,up[i][j]-low[i][j]); 156 d[i]+=low[i][j]; 157 d[j+n]-=low[i][j]; 158 } 159 } 160 int tot=0; 161 for(int i=S; i<=T; ++i){ 162 if(d[i]<0) addEdge(vs,i,-d[i]); 163 else addEdge(i,vt,d[i]),tot+=d[i]; 164 } 165 if(flag || ISAP()!=tot){ 166 puts("IMPOSSIBLE"); 167 if(t) putchar('\n'); 168 continue; 169 } 170 for(int u=1; u<=n; ++u){ 171 for(int i=head[u]; i!=-1; i=edge[i].next){ 172 if(i&1) continue; 173 int v=edge[i].v; 174 low[u][v-n]+=edge[i].flow; 175 } 176 } 177 for(int i=1; i<=n; ++i){ 178 for(int j=1; j<=m; ++j){ 179 printf("%d ",low[i][j]); 180 } 181 putchar('\n'); 182 } 183 if(t) putchar('\n'); 184 } 185 return 0; 186 }