http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1994
http://poj.org/problem?id=2396
题目大意:给一个m行n列的空矩阵,让你往上面填数(数为非负整数),使得这个矩阵满足:
1.每行/列和等于给定的每行/列和
2.一些限制条件。
限制条件限制了x,y,ch,v,使得x行y列的点的数满足(>or=or<,由ch决定)v。
特别的,如果x=0则代表y列全满足该条件,如果y=0则代表x行全满足该条件,如果全为0则代表全矩阵全满足该条件。
——————————————————————————
有二分图+上下界网络流想法,不难想到先建源汇点,源点到所有的行连一条上下界均为行和的边,所有的列到汇点连一条上下界均为列和的边。
然后整理限制条件,行和列之间连满足所有限制条件的边。
在那之后就是上下界网络流的活了。
注意:
1.可以先判断行和之和如果不等于列和之和的话就是IMPOSSIBLE。
2.限制条件如果不满足的话||第一条发生的话,记得把剩余的限制条件读完再输出。
3.我们其实可以简化,我们其实根本不需要源汇点,于是它其实可以转换成无源汇上下界网络流可行流。
原因:最开始建源汇点的时候我们发现它只连了上下界相同的边,相当于没连,以致到后来跑可行流的时候它根本不会做出任何贡献,所以大可以删掉。
4.IMPOSSIBLE不要打错……
5.ZOJ选手注意,不能填负数,最后一行不能有两个回车。
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=405; const int M=2000005; const int INF=1e9; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==‘-‘;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int nxt,to,w; }edge[M]; int head[N],du[N],up[205][205],low[205][205]; int cnt=-1,S,T; bool die[205][205]; inline void add(int u,int v,int w){ cnt++; edge[cnt].to=v; edge[cnt].w=w; edge[cnt].nxt=head[u]; head[u]=cnt; return; } int lev[N],cur[N],dui[N]; bool bfs(int k){ int r=0; for(int i=1;i<=k;i++){ lev[i]=-1; cur[i]=head[i]; } dui[0]=S,lev[S]=0; int u,v; for(int l=0;l<=r;l++){ u=dui[l]; for(int e=head[u];e!=-1;e=edge[e].nxt){ v=edge[e].to; if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1; r++; dui[r]=v; if(v==T)return 1; } } } return 0; } int dinic(int u,int flow,int k){ if(u==k)return flow; int res=0,delta; for(int &e=cur[u];e!=-1;e=edge[e].nxt){ int v=edge[e].to; if(edge[e].w>0&&lev[u]<lev[v]){ delta=dinic(v,min(edge[e].w,flow-res),k); if(delta>0){ edge[e].w-=delta; edge[e^1].w+=delta; res+=delta; if(res==flow)break; } } } if(res!=flow)lev[u]=-1; return res; } inline void init(int m,int n){ memset(head,-1,sizeof(head)); memset(du,0,sizeof(du)); memset(die,0,sizeof(die)); for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ up[i][j]=INF; low[i][j]=0; } } cnt=-1; return; } inline char getc(){ char ch=‘ ‘; while(ch==‘ ‘)ch=getchar(); return ch; } int main(){ int t=read(),num=0; while(t--){ num++; if(num>1)puts(""); int m=read(),n=read(); init(m,n); int tot=0; for(int i=1;i<=m;i++){ int h=read(); du[i]+=h; tot+=h; } for(int i=1;i<=n;i++){ int l=read(); du[i+m]-=l; tot-=l; } int c=read(); bool flag=1; for(int i=1;i<=c;i++){ int r=read(),q=read(),a,b; char ch=getc(); int v=read(); if(ch==‘<‘){a=0;b=--v;} else if(ch==‘>‘){a=++v;b=INF;} else a=b=v; if(!r&&!q){ for(int j=1;j<=m&&flag;j++){ for(int k=1;k<=n&&flag;k++){ if(die[j][k]&&(low[j][k]>b||low[j][k]<a)){ flag=0; break; } if(ch==‘=‘){up[j][k]=low[j][k]=v;die[j][k]=1;} else if(ch==‘>‘)low[j][k]=max(low[j][k],v); else up[j][k]=min(up[j][k],v); if(low[j][k]>up[j][k])flag=0; } } }else if(!r){ for(int j=1;j<=m&&flag;j++){ if(die[j][q]&&(low[j][q]>b||low[j][q]<a)){ flag=0; break; } if(ch==‘=‘){up[j][q]=low[j][q]=v;die[j][q]=1;} else if(ch==‘>‘)low[j][q]=max(low[j][q],v); else up[j][q]=min(up[j][q],v); if(low[j][q]>up[j][q])flag=0; } }else if(!q){ for(int k=1;k<=n&&flag;k++){ if(die[r][k]&&(low[r][k]>b||low[r][k]<a)){ flag=0; break; } if(ch==‘=‘){up[r][k]=low[r][k]=v;die[r][k]=1;} else if(ch==‘>‘)low[r][k]=max(low[r][k],v); else up[r][k]=min(up[r][k],v); if(low[r][k]>up[r][k])flag=0; } }else{ if(die[r][q]&&(low[r][q]>b||low[r][q]<a)){ flag=0; } if(ch==‘=‘){up[r][q]=low[r][q]=v;die[r][q]=1;} else if(ch==‘>‘)low[r][q]=max(low[r][q],v); else up[r][q]=min(up[r][q],v); if(low[r][q]>up[r][q])flag=0; } } if(!flag||tot!=0){ puts("IMPOSSIBLE"); continue; } for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ add(i,j+m,up[i][j]-low[i][j]); add(j+m,i,0); du[i]-=low[i][j]; du[j+m]+=low[i][j]; } } S=m+n+1;T=S+1; int ans=0,full=0; for(int i=1;i<=m+n;i++){ if(du[i]>0){ add(S,i,du[i]); add(i,S,0); full+=du[i]; }else if(du[i]<0){ add(i,T,-du[i]); add(T,i,0); } } while(bfs(T))ans+=dinic(S,INF,T); if(ans!=full)puts("IMPOSSIBLE"); else{ for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ int id=((i-1)*n+j)*2-1; printf("%d",low[i][j]+edge[id].w); if(j!=n)putchar(‘ ‘); } puts(""); } } } return 0; }