POJ 2396 Budget ——有上下界的网络流
给定矩阵的每行每列的和,和一些大于小于等于的限制。然后需要求出一组可行解。
上下界网络流。
大概的思想就是计算出每一个点他需要强行流入或者流出的量,然后建出超级源点和汇点,然后删除下界,就可以判断是否可行。
然后把新的上界作为限制,在原图中跑一边。
然后就是必须的+原图中的进行计算。
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) int up[205][205],down[205][205],tt,n,m,row[205]; #define inf 0x3f3f3f3f #define maxn 50005 int ttt,clu[205],S=maxn-4,T=maxn-3,SS=maxn-2,TT=maxn-1; int fr[maxn],h[maxn],to[maxn],ne[maxn],fl[maxn],en=0,ans,a[205][205]; int du[maxn],id[205][205],tot,Sum,s,t,ban[maxn],SSum,SSSum; void add(int a,int b,int c) { fr[en]=a;to[en]=b;ne[en]=h[a];fl[en]=c;h[a]=en++; fr[en]=b;to[en]=a;ne[en]=h[b];fl[en]=0;h[b]=en++; } int dis[maxn]; queue<int>q; bool tell() { memset(dis,-1,sizeof dis); dis[s]=0; q.push(s); while (!q.empty()) { int x=q.front();q.pop(); for (int i=h[x];i>=0;i=ne[i]) if (dis[to[i]]==-1&&fl[i]>0&&!ban[i]) dis[to[i]]=dis[x]+1,q.push(to[i]); } return dis[t]!=-1; } int zeng(int k,int now) { int ret=0; if (k==t) return now; for (int i=h[k];i>=0&&now>ret;i=ne[i]) if (dis[to[i]]==dis[k]+1&&fl[i]&&!ban[i]){ int tmp=zeng(to[i],min(fl[i],now-ret)); fl[i]-=tmp; fl[i^1]+=tmp; ret+=tmp; } if (!ret) dis[k]=-1; return ret; } int dinic(int S,int T) { int ret=0,tmp=0;//printf("dinic %d %d\n",S,T); s=S;t=T; while (tell()) while (tmp=zeng(s,inf)) ret+=tmp; return ret; } void build() { en=0;memset(h,-1,sizeof h);memset(a,0,sizeof a); memset(du,0,sizeof du); memset(ban,0,sizeof ban);Sum=0; tot=0; F(i,1,n) F(j,1,m) { if (up[i][j]<down[i][j]) {ans=0;return;} du[i]-=down[i][j]; du[j+n]+=down[i][j]; up[i][j]-=down[i][j]; a[i][j]+=down[i][j]; add(i,j+n,up[i][j]); } F(i,1,n) add(S,i,row[i]); F(j,n+1,n+m) add(j,T,clu[j-n]); add(T,S,inf); F(i,1,n+m) { if (du[i]>0) add(SS,i,du[i]),Sum+=du[i]; else if (du[i]<0) add(i,TT,-du[i]); } if (dinic(SS,TT)!=Sum) {ans=0;return;} else { ban[en-1]=1;ban[en-2]=1; for (int i=h[SS];i>=0;i=ne[i]) ban[i]=ban[i^1]=1; for (int i=h[TT];i>=0;i=ne[i]) ban[i]=ban[i^1]=1; if (dinic(S,T)!=SSum) {ans=0;return;} F(i,1,n) { for (int j=h[i];j>=0;j=ne[j]) a[i][to[j]-n]+=fl[j^1]; } ans=1; return; } } int main() { scanf("%d",&tt); while (tt--) { memset(down,0,sizeof down); memset(up,0x3f,sizeof up); scanf("%d%d",&n,&m);SSum=SSSum=0; F(i,1,n) scanf("%d",&row[i]),SSum+=row[i]; F(i,1,m) scanf("%d",&clu[i]),SSSum+=clu[i]; scanf("%d",&ttt); F(i,1,ttt) { int x,y,z;char s[11]; scanf("%d%d%s%d",&x,&y,s,&z); switch(s[0]) { case '>': if (!x) F(i,1,n) { if (!y) F(j,1,m) down[i][j]=max(down[i][j],z+1); else down[i][y]=max(down[i][y],z+1); } else { if (!y) F(j,1,m) down[x][j]=max(down[x][j],z+1); else down[x][y]=max(down[x][y],z+1); } break; case '=': if (!x) F(i,1,n) { if (!y) F(j,1,m) { up[i][j]=min(up[i][j],z); down[i][j]=max(down[i][j],z); } else { up[i][y]=min(up[i][y],z); down[i][y]=max(down[i][y],z); } } else { if (!y) F(j,1,m) { up[x][j]=min(up[x][j],z); down[x][j]=max(down[x][j],z); } else { up[x][y]=min(up[x][y],z); down[x][y]=max(down[x][y],z); } } break; case '<': if (!x) F(i,1,n) { if (!y) F(j,1,m) up[i][j]=min(up[i][j],z-1); else up[i][y]=min(up[i][y],z-1); } else { if (!y) F(j,1,m) up[x][j]=min(up[x][j],z-1); else up[x][y]=min(up[x][y],z-1); } break; } } build(); if ((!ans)||(SSum!=SSSum)) printf("IMPOSSIBLE\n"); else { F(i,1,n) F(j,1,m) printf("%d%c",a[i][j],j==m?'\n':' '); } if (tt!=0) printf("\n"); } }