http://poj.org/problem?id=2396 (题目链接)
题意
给出一个矩阵,给出每一行每一列的和,以及若干限制条件,限制了其中每一个元素的上下界,求一种可行的方案使得每一行每一列数的和满足要求。
Solution
我已经完全没有网络流思维了,江化了= 。=
源点向每一行和每一列连上下界都为其对应和的边,行与列之间连边,边的上下界为对应格子的取值范围。然后跑上下界网络流找一条可行流就可以了。
细节
mdzz初值设太大爆int了= =,还有这种事。。
代码
// poj2396 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #define LL long long #define inf (1ll<<29) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout) using namespace std; const int maxn=1010; int head[maxn],fi[maxn],d[maxn],upp[maxn][maxn],low[maxn][maxn],id[maxn][maxn]; int n,m,s,c,t,S,T,SS,TT,cnt,sum,flag; struct edge {int to,next,w;}e[maxn*maxn]; void link(int u,int v,int w) { e[++cnt]=(edge){v,head[u],w};head[u]=cnt; e[++cnt]=(edge){u,head[v],0};head[v]=cnt; } bool bfs() { memset(d,-1,sizeof(d)); queue<int> q;q.push(s);d[s]=0; while (!q.empty()) { int x=q.front();q.pop(); for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]<0) d[e[i].to]=d[x]+1,q.push(e[i].to); } return d[t]>0; } int dfs(int x,int f) { if (x==t || f==0) return f; int w,used=0; for (int i=head[x];i;i=e[i].next) if (e[i].w && d[e[i].to]==d[x]+1) { w=dfs(e[i].to,min(e[i].w,f-used)); used+=w,e[i].w-=w,e[i^1].w+=w; if (used==f) return used; } if (!used) d[x]=-1; return used; } int Dinic(int x,int y) { int flow=0;s=x,t=y; while (bfs()) flow+=dfs(x,inf); return flow; } void modify(int x,int y,char *r,int val) { if (r[0]=='<') upp[x][y]=min(upp[x][y],val-1); if (r[0]=='>') low[x][y]=max(low[x][y],val+1); if (r[0]=='=') { if (val>=low[x][y] && val<=upp[x][y]) upp[x][y]=low[x][y]=val; else flag=0; } } int main() { int Case;scanf("%d",&Case); while (Case--) { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) upp[i][j]=1000,low[i][j]=0; memset(head,0,sizeof(head)); memset(fi,0,sizeof(fi)); S=0,T=n+m+1;SS=T+1,TT=SS+1; cnt=1;sum=0;flag=1; for (int x,i=1;i<=n;i++) { scanf("%d",&x); fi[S]-=x,fi[i]+=x; } for (int x,i=1;i<=m;i++) { scanf("%d",&x); fi[T]+=x,fi[i+n]-=x; } scanf("%d",&c);char ch[10]; for (int x,y,z,i=1;i<=c;i++) { scanf("%d%d%s%d",&x,&y,ch,&z); if (!x && !y) for (int j=1;j<=n;j++) for (int k=1;k<=m;k++) modify(j,k,ch,z); else if (!x) for (int j=1;j<=n;j++) modify(j,y,ch,z); else if (!y) for (int j=1;j<=m;j++) modify(x,j,ch,z); else modify(x,y,ch,z); } for (int i=1;i<=n && flag;i++) for (int j=1;j<=m && flag;j++) { if (low[i][j]<=upp[i][j]) { fi[i]-=low[i][j],fi[n+j]+=low[i][j]; link(i,n+j,upp[i][j]-low[i][j]); id[i][j]=cnt-1; } else flag=0; } if (!flag) {puts("IMPOSSIBLE ");continue;} for (int i=S;i<=T;i++) { if (fi[i]<0) link(i,TT,-fi[i]); else link(SS,i,fi[i]),sum+=fi[i]; } link(T,S,inf); if (sum!=Dinic(SS,TT)) {puts("IMPOSSIBLE ");continue;} for (int i=1;i<=n;i++) { for (int j=1;j<=m;j++) printf("%d ",low[i][j]+e[id[i][j]^1].w); puts(""); } puts(""); } return 0; }