题意:
给一个矩阵的每行和及每列和,在给一些行列或点的限制条件。求一个满足的矩阵。
分析:
转化为有上下界的网络流,注意等于也是一种上下界关系,然后用dinic算法。
代码:
//poj 2396 //sep9 #include <iostream> #include <queue> #include <algorithm> using namespace std; const int maxN=210; const int maxM=40; const int maxV=260; const int maxE=26000; struct Edge { int u,v,f,nxt; }e[maxE*2+10]; queue<int> que; int src,sink; int g[maxV+10]; int nume; bool vis[maxV+10]; int dist[maxV+10]; int N,M,low[maxN][maxM],high[maxN][maxM],ids[maxN][maxM],R[maxN],C[maxM]; int SS,TT; void addedge(int u,int v,int c) { e[nume].u=u,e[nume].v=v;e[nume].f=c;e[nume].nxt=g[u];g[u]=nume++; e[nume].u=v;e[nume].v=u;e[nume].f=0;e[nume].nxt=g[v];g[v]=nume++; } void update(int x1,int x2,int y1,int y2,char op,int z) { for(int i=x1;i<=x2;++i) for(int j=y1;j<=y2;++j){ if(op=='=') low[i][j]=max(low[i][j],z),high[i][j]=min(high[i][j],z); else if(op=='<') high[i][j]=min(high[i][j],z-1); else low[i][j]=max(low[i][j],z+1); } } int check() { for(int i=1;i<=N;++i) for(int j=1;j<=M;++j) if(low[i][j]>high[i][j]) return 0; return 1; } void init() { memset(g,0,sizeof(g)); nume=2; int i,j,k,x,y,z,c; char op[16]; scanf("%d%d",&N,&M); memset(low,0,sizeof(low)),memset(high,0x7f,sizeof(high)); for(i=1;i<=N;++i) scanf("%d",&R[i]); for(i=1;i<=M;++i) scanf("%d",&C[i]); scanf("%d",&c); while(c--){ scanf("%d%d%s%d",&x,&y,op,&z); if(x==0&&y==0) update(1,N,1,M,op[0],z); else if(x==0) update(1,N,y,y,op[0],z); else if(y==0) update(x,x,1,M,op[0],z); else update(x,x,y,y,op[0],z); } } int bfs() { while(!que.empty()) que.pop(); memset(dist,0,sizeof(dist)); memset(vis,0,sizeof(vis)); vis[src]=true; que.push(src); while(!que.empty()){ int u=que.front();que.pop(); for(int i=g[u];i;i=e[i].nxt) if(e[i].f&&!vis[e[i].v]){ que.push(e[i].v); dist[e[i].v]=dist[u]+1; vis[e[i].v]=true; if(e[i].v==sink) return 1; } } return 0; } int dfs(int u,int delta) { if(u==sink) return delta; int ret=0; for(int i=g[u];ret<delta&&i;i=e[i].nxt) if(e[i].f&&dist[e[i].v]==dist[u]+1){ int dd=dfs(e[i].v,min(e[i].f,delta-ret)); if(dd>0){ e[i].f-=dd; e[i^1].f+=dd; ret+=dd; } else dist[e[i].v]=-1; } return ret; } int dinic() { int ret=0; while(bfs()==1) ret+=dfs(src,INT_MAX); return ret; } int build() { int i,j,sum=0; src=0,sink=N+M+1,SS=sink+1;TT=sink+2; addedge(sink,src,INT_MAX); for(i=1;i<=N;++i){ addedge(SS,i,R[i]);addedge(src,TT,R[i]); sum+=R[i]; } for(i=1;i<=M;++i){ addedge(SS,sink,C[i]);addedge(N+i,TT,C[i]); sum+=C[i]; } for(i=1;i<=N;++i) for(j=1;j<=M;++j){ ids[i][j]=nume+1; addedge(i,N+j,high[i][j]-low[i][j]); addedge(SS,N+j,low[i][j]); addedge(i,TT,low[i][j]); sum+=low[i][j]; } return sum; } void solve() { if(!check()){ puts("IMPOSSIBLE"); return ; } int sum=build(); src=SS,sink=TT; if(sum!=dinic()) puts("IMPOSSIBLE"); else{ for(int i=1;i<=N;++i){ for(int j=1;j<=M;++j) printf("%d ",e[ids[i][j]].f+low[i][j]); printf(" "); } } } int main() { int cases; scanf("%d",&cases); while(cases--){ init(); solve(); printf(" "); } return 0; }