题意简述:给定矩阵(每个元素都是非负整数)各行各列的和,并且限制其中的某些元素,给出一个可行解,特殊评测。矩阵规模小于200*20。
网络流的模型是显而易见的,不过对于这道题,我们要添加两次源和汇。
第一次添加s连接每一行,t连接每一列,容量上下线都是这行或这列的和。
第二次对每条有容量限制的边(u,v)添加 (ss,v)和( u,tt)容量均为( u,v)的下限。
第三次添加(t,s)容量无穷。
对(ss,tt)求最大流,若ss出发和进入tt的边均满流则有解,并且可以直接输出解。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<vector> #include<cstring> #include<algorithm> #include<queue> using namespace std; const int maxm=200+50,INF=1e+8; int k,ans[maxm][maxm],cap[maxm][maxm],flow[maxm][maxm],low[maxm][maxm],up[maxm][maxm],n,m; vector<int> next[maxm]; int d[maxm],fa[maxm],cur[maxm]; bool vis[maxm]; bool bfs(int s,int t) { memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); queue<int>q; vis[s]=true;q.push(s); while(!q.empty()) { int np=q.front();q.pop(); for(int i=0;i<next[np].size();i++) { int ne=next[np][i]; if(cap[np][ne]<=flow[np][ne]||vis[ne])continue; q.push(ne); vis[ne]=true; d[ne]=d[np]+1; } } return vis[t]; } int dfs(int now,int t,int flo) { if(now==t||flo==0)return flo; int floww=0; for(int i=cur[now];i<next[now].size();i++) { int np=next[now][i]; if(d[np]!=d[now]+1)continue; if(cap[now][np]<=flow[now][np])continue; int fn=dfs(np,t,min(flo,cap[now][np]-flow[now][np])); flow[now][np]+=fn; flow[np][now]-=fn; floww+=fn; flo-=fn; if(flo==0)break; cur[now]++; } return floww; } int dinic(int s,int t) { int ans=0; while(bfs(s,t)) { memset(cur,0,sizeof(cur)); ans+=dfs(s,t,INF); } return ans; } void find(int s,int t) { memset(d,0,sizeof(d)); d[s]=INF; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<next[u].size();i++) { int nextp=next[u][i]; if(d[nextp]!=0||(cap[u][nextp]-flow[u][nextp])<=0)continue; d[nextp]=min(d[u],(cap[u][nextp]-flow[u][nextp])); q.push(nextp); fa[nextp]=u; if(nextp==t) { while(!q.empty())q.pop(); return ; } } } } int E_K(int s,int t) { int ans=0; memset(fa,0,sizeof(fa)); while(true) { find(s,t); ans+=d[t]; if(d[t]==0)break; for(int i=t;i!=s;i=fa[i]) { flow[fa[i]][i]+=d[t]; flow[i][fa[i]]-=d[t]; } } return ans; } void addedge(int a,int b,vector<int> next[]) { next[a].push_back(b); next[b].push_back(a); return ; } int main() { int N; int s=249,t=s-1,ss=t-1,tt=ss-1; scanf("%d",&N); for(int ii=1;ii<=N;ii++) { for(int i=0;i<maxm;i++) while(next[i].size()>0)next[i].pop_back(); memset(cap,0,sizeof(cap));memset(flow,0,sizeof(flow)); memset(low,0,sizeof(low));memset(up,0,sizeof(up)); scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) { int a;scanf("%d",&a); cap[s][i]=0;cap[ss][i]+=a;cap[s][tt]+=a; addedge(s,i,next);addedge(ss,i,next);addedge(i,tt,next); for(int j=201;j<=200+n;j++) { addedge(i,j,next); up[i][j]=a; } } addedge(s,tt,next); for(int i=201;i<=200+n;i++) { int a;scanf("%d",&a); cap[i][t]=0;cap[ss][t]+=a;cap[i][tt]+=a; addedge(i,t,next);addedge(i,tt,next);addedge(i,ss,next); for(int j=1;j<=m;j++) up[j][i]=min(up[j][i],a); } addedge(ss,t,next); int k; scanf("%d",&k); for(int iii=0;iii<k;iii++) { int a,b,c;char t; scanf("%d%d",&a,&b);t=getchar();t=getchar();scanf("%d",&c); int ia,ib,ja,jb; if(a==0){ia=1;ib=m;} else {ia=ib=a;} if(b==0){ja=201;jb=200+n;} else{ja=jb=(200+b);} for(int i=ia;i<=ib;i++) for(int j=ja;j<=jb;j++) { if(t=='=') { up[i][j]=min(up[i][j],c);low[i][j]=max(low[i][j],c); } if(t=='>') { low[i][j]=max(low[i][j],c+1); } if(t=='<') { up[i][j]=min(up[i][j],c-1); } } } for(int i=1;i<=m;i++) for(int j=201;j<=200+n;j++) { cap[i][j]=up[i][j]-low[i][j]; cap[ss][j]+=low[i][j]; cap[i][tt]+=low[i][j]; } next[t].push_back(s);cap[t][s]=INF; dinic(ss,tt); bool impo=false; for(int i=1;i<=m;i++) { if(flow[ss][i]!=cap[ss][i]){impo=true;break;} if(flow[i][tt]!=cap[i][tt]){impo=true;break;} } for(int j=201;j<=200+n;j++) { if(flow[ss][j]!=cap[ss][j]){impo=true;break;} if(flow[j][tt]!=cap[j][tt]){impo=true;break;} } if(flow[s][tt]!=cap[s][tt]){impo=true;} if(flow[ss][t]!=cap[ss][t]){impo=true;} if(impo){printf("IMPOSSIBLE\n\n");continue;} for(int i=1;i<=m;i++) { for(int j=201;j<n+200;j++) { printf("%d ",flow[i][j]+low[i][j]); } printf("%d\n",flow[i][200+n]+low[i][200+n]); } printf("\n"); } return 0; }