题目:
题意:
有一个n*m的非负整数矩阵(n<=20,m<=200),给定每行之和和每列之和,并对一些格子进行约束
例如:
1 2 > 2代表(1,2)格子里的数大于2
0 1 = 2表示第1列的所有数字都等于2
求一种可能的矩阵
题解:
这怎么既有行又有列?我要是设置了行和列怎么代表点呢?诶等等,一行+一列不就对应一个点吗= =
那么我们建图就设置两列,一列表示 行,一列表示 列,连边代表限制,行与列之间的连边代表点的限制,但他们既然是一个矩阵,和上一道题那个一圈的管道不一样,本身就是有源有汇的
xi表示行,yi表示列,s-xi[sumx,sumx],yi-t[sumy,sumy]
和无源汇有上下界的可行流类似,只需要加一条边t->s,限制为[0,inf]就可以了,相当于是让源点和汇点也满足流量平衡
然后再建立附加源汇ss,tt,其余的就和无源汇的一样了
证明什么的都类似无源汇啦
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define INF 1e9
const int N=15000;
int tot=-1,maxflow,in,out,point[N],nxt[N],v[N],remind[N],cur[N],dis[N],d[N];
int l[205][500],r[205][500],pipe[205][500];
void cl()
{
in=out=0;maxflow=0;memset(l,0,sizeof(l));memset(r,0x7f,sizeof(r));
tot=-1;memset(point,-1,sizeof(point));memset(nxt,-1,sizeof(nxt));
memset(d,0,sizeof(d));
}
void addline(int x,int y,int cap)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remind[tot]=cap;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remind[tot]=0;
}
int dfs(int now,int t,int limit)
{
if (now==t || !limit) return limit;
int flow=0,f;
for (int i=cur[now];i!=-1;i=nxt[i])
{
cur[now]=i;
if (dis[v[i]]==dis[now]+1 && (f=dfs(v[i],t,min(limit,remind[i]))))
{
limit-=f;
flow+=f;
remind[i]-=f;
remind[i^1]+=f;
if (!limit) break;
}
}
return flow;
}
bool bfs(int s,int t)
{
queue<int>q;
q.push(s);
memset(dis,0x7f,sizeof(dis));
for (int i=1;i<=t;i++) cur[i]=point[i];
dis[s]=0;
while (!q.empty())
{
int x=q.front(); q.pop();
for (int i=point[x];i!=-1;i=nxt[i])
if (dis[v[i]]>INF && remind[i])
{q.push(v[i]); dis[v[i]]=dis[x]+1;}
}
return dis[t]<INF;
}
int main()
{
int T,n,m,x,lj,y,z,s,t,ss,tt;char fh[5];
scanf("%d",&T);
while (T--)
{
cl();
scanf("%d%d",&n,&m);
s=n+m+1; t=s+1; ss=t+1; tt=ss+1;
for (int i=1;i<=n;i++) scanf("%d",&x),d[s]-=x,d[i]+=x;
for (int i=1;i<=m;i++) scanf("%d",&x),d[i+n]-=x,d[t]+=x;
scanf("%d",&lj);
while (lj--)
{
scanf("%d%d%s%d",&x,&y,&fh,&z);
if (!x && !y)
{
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (fh[0]=='=') l[i][j]=r[i][j]=z;
if (fh[0]=='>') l[i][j]=max(l[i][j],z+1);
if (fh[0]=='<') r[i][j]=min(r[i][j],z-1);
}
}
else if (!y)
{
for (int j=1;j<=m;j++)
{
if (fh[0]=='=') l[x][j]=r[x][j]=z;
if (fh[0]=='>') l[x][j]=max(l[x][j],z+1);
if (fh[0]=='<') r[x][j]=min(r[x][j],z-1);
}
}
else if (!x)
{
for (int i=1;i<=n;i++)
{
if (fh[0]=='=') l[i][y]=r[i][y]=z;
if (fh[0]=='>') l[i][y]=max(l[i][y],z+1);
if (fh[0]=='<') r[i][y]=min(r[i][y],z-1);
}
}
else
{
if (fh[0]=='=') l[x][y]=r[x][y]=z;
if (fh[0]=='>') l[x][y]=max(l[x][y],z+1);
if (fh[0]=='<') r[x][y]=min(r[x][y],z-1);
}
}
addline(t,s,INF);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
addline(i,j+n,r[i][j]-l[i][j]),d[i]-=l[i][j],d[j+n]+=l[i][j],pipe[i][j]=tot;
for (int i=1;i<=t;i++)
{
if (d[i]>0) addline(ss,i,d[i]),in+=d[i];
if (d[i]<0) addline(i,tt,-d[i]),out-=d[i];
}
if (in!=out) {printf("IMPOSSIBLE\n\n");continue;}
while (bfs(ss,tt)) maxflow+=dfs(ss,tt,INF);
if (maxflow!=in) {printf("IMPOSSIBLE\n\n");continue;}
else
{
for (int i=1;i<=n;i++)
{
for (int j=1;j<m;j++) printf("%d ",remind[pipe[i][j]]+l[i][j]);
printf("%d\n",remind[pipe[i][m]]+l[i][m]);
}
printf("\n");
}
}
}