题意:
cas //测试数据组数
n m //行数 列数
a1 a2 ... an //每行的和
b1 b2 ... bn //每列的和
q //操作数量
//接下来q行
a b >/</= c //若a为0则表示一整列,b为0表示一整行,否则a代表第几行,b代表第几列,操作表示选中区域或者某个元素要严格大于或者严格小于或者等于c
求:判断是否存在合法矩阵,如果存在输出任一合法矩阵(每个元素都要求非负),否则输出“IMPOSSIBLE”
思路:
上马基的时候自己想了想,首先是各种基础的操作判断给出的各项限制之间有没有矛盾,然后最大流跑下判断。
根据给出的限制,每个元素都有下限和上限,然后把下限单独从总的流中拿出来,用剩下的区间的值跑下最大流,看最后最大流的流量是否是去除每个元素下限之后的所有的元素的和。
坑:
1.这题是多组输入数据,如果判断出不可能直接return 0;这种愚蠢的行为出现在我的代码上了。已经无力吐槽。
2.建图。一开始我的建图的方法是每个元素在图中表示一个点,然后左端是表示行的点右端是表示列的点,然后连起来。当时感觉好像还不错,保证每个点对行和列的贡献是一样的...然后就开始各种超时了,一直找原因,直到找到大神的代码...真是tmsb,其实这种点的度数为2而且两条边的容量是相等的情况下,完全可以把这点省略,去除了n*m个点就过了...
不管怎么样,有坑都是好事。
#include<stdio.h> #include<string.h> #include<algorithm> #include<string.h> #include<vector> #define MAXN 4050 #define MAXM 40050 using namespace std; const int inf=0x3f3f3f3f; int hang[205],lie[25]; int mmax[205][25],mmin[205][25]; struct Edge { int v,c,f,nx; Edge() {} Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {} } E[MAXM]; int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],sz; void init() { sz=0; memset(G,-1,sizeof(G)); } void add_edge(int u,int v,int c) { E[sz]=Edge(v,c,0,G[u]); G[u]=sz++; E[sz]=Edge(u,0,0,G[v]); G[v]=sz++; } bool bfs(int S,int T) { static int Q[MAXN]; memset(dis,-1,sizeof(dis)); dis[S]=0; Q[0]=S; for (int h=0,t=1,u,v,it; h<t; ++h) { for (u=Q[h],it=G[u]; ~it; it=E[it].nx) { if (dis[v=E[it].v]==-1&&E[it].c>E[it].f) { dis[v]=dis[u]+1; Q[t++]=v; } } } return dis[T]!=-1; } int dfs(int u,int T,int low) { if (u==T) return low; int ret=0,tmp,v; for (int &it=cur[u]; ~it&&ret<low; it=E[it].nx) { if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f) { if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f))) { ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp; } } } if (!ret) dis[u]=-1; return ret; } int dinic(int S,int T) { int maxflow=0,tmp; while (bfs(S,T)) { memcpy(cur,G,sizeof(G)); while (tmp=dfs(S,T,inf)) maxflow+=tmp; } return maxflow; } int main() { int cas; scanf("%d",&cas); while(cas--) { bool ok=1; memset(mmin,0,sizeof(mmin)); init(); int n,m,x,y,z,k; char typ[5]; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { mmax[i][j]=inf; } } for(int i=1; i<=n; i++) { scanf("%d",&hang[i]); } for(int i=1; i<=m; i++) { scanf("%d",&lie[i]); } scanf("%d",&k); for(int i=1; i<=k; i++) { scanf("%d%d%s%d",&x,&y,typ,&z); if(x==0) { if(y==0) { for(int j=1; j<=n; j++) { for(int kk=1; kk<=m; kk++) { if(typ[0]=='<') { mmax[j][kk]=min(mmax[j][kk],z-1); } else if(typ[0]=='>') { mmin[j][kk]=max(mmin[j][kk],z+1); } else { mmax[j][kk]=min(mmax[j][kk],z); mmin[j][kk]=max(mmin[j][kk],z); } } } } else { for(int j=1; j<=n; j++) { if(typ[0]=='<') { mmax[j][y]=min(mmax[j][y],z-1); } else if(typ[0]=='>') { mmin[j][y]=max(mmin[j][y],z+1); } else { mmax[j][y]=min(mmax[j][y],z); mmin[j][y]=max(mmin[j][y],z); } } } } else { if(y==0) { for(int j=1; j<=m; j++) { if(typ[0]=='<') { mmax[x][j]=min(mmax[x][j],z-1); } else if(typ[0]=='>') { mmin[x][j]=max(mmin[x][j],z+1); } else { mmax[x][j]=min(mmax[x][j],z); mmin[x][j]=max(mmin[x][j],z); } } } else { if(typ[0]=='<') { mmax[x][y]=min(mmax[x][y],z-1); } else if(typ[0]=='>') { mmin[x][y]=max(mmin[x][y],z+1); } else { mmax[x][y]=min(mmax[x][y],z); mmin[x][y]=max(mmin[x][y],z); } } } } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { if(mmax[i][j]<0||mmax[i][j]<mmin[i][j]) { ok=0; break; } hang[i]-=mmin[i][j]; lie[j]-=mmin[i][j]; if(hang[i]<0||lie[j]<0) { ok=0; break; } } } int ans1,ans2; if(ok){ for(int i=1; i<=n; i++) { add_edge(0,i,hang[i]); } for(int i=n+1; i<=m+n; i++) { add_edge(i,n+m+1,lie[i-n]); } for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { add_edge(i,n+j,mmax[i][j]-mmin[i][j]); } } ans1=0,ans2=0; for(int i=1; i<=n; i++) { ans1+=hang[i]; } for(int i=1; i<=m; i++) { ans2+=lie[i]; } if(ans1!=ans2) { ok=0; }} if(ok){ if(dinic(0,m+n+1)==ans1) { memcpy(cur,G,sizeof(G)); for(int i=1; i<=n; i++) { for(int j=1; j<=m; j++) { int v; for (int it=cur[i]; ~it; it=E[it].nx) { v=E[it].v; if (v==n+j) { printf("%d ",E[it].f+mmin[i][j]); break; } } } puts(""); } } else { ok=0; }} if(ok==0)puts("IMPOSSIBLE"); if(cas)puts(""); } }