这个题算是上下界的网络流,看出来它是上下界的网络流其实不难。建图的时候以行列进行分点,先设定源点并对所有的列或行进行连边,流量为所给的和。再设定汇点并连接所有的行或列点,流量同样为和。然后可以看出行和列的流量应该为下界为1上界为20,然后根据上下界网络流的求法,设定超级源点和汇点,然后再拆边跑2次最大流就行了
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const int inf=1<<29;
const int maxn=500;
const int maxm=maxn*maxn;
int e,s,t,st,des,n,m,row[maxn],col[maxn],head[maxn],pnt[maxm],nxt[maxm],flow[maxm],level[maxn];
int ans[maxn][maxn];
queue<int> q;
void AddEdge(int u,int v,int f)
{
pnt[e]=v;nxt[e]=head[u];flow[e]=f;head[u]=e++;
pnt[e]=u;nxt[e]=head[v];flow[e]=0;head[v]=e++;
}
bool BFS()
{
memset(level,0,sizeof(level));
level[st]=1;
q.push(st);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=nxt[i])
if(flow[i]&&!level[pnt[i]])
{
level[pnt[i]]=level[u]+1;
q.push(pnt[i]);
}
}
return level[des];
}
int DFS(int u,int maxf)
{
if(u==des||!maxf)
return maxf;
for(int i=head[u],t;i!=-1;i=nxt[i])
if(level[pnt[i]]==level[u]+1&&(t=DFS(pnt[i],min(flow[i],maxf))))
{
flow[i]-=t;
flow[i^1]+=t;
return t;
}
return level[u]=0;
}
void maxflow()
{
int ans=0;
while(BFS())
while(1)
{
int val=DFS(st,inf);
if(!val)
break;
ans+=val;
}
}
void Build()
{
e=s=0;t=n+m+1;
st=n+m+2,des=n+m+3;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
AddEdge(s,i,row[i]-row[i-1]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
AddEdge(i,des,1);
AddEdge(i,n+j,19);
AddEdge(st,n+j,1);
}
for(int i=1;i<=m;i++)
AddEdge(n+i,t,col[i]-col[i-1]);
AddEdge(t,s,inf);
}
void solve()
{
maxflow();
st=0,des=n+m+1;
maxflow();
for(int i=0;i<e;i+=2)
{
if(pnt[i^1]>s&&pnt[i^1]<=n&&pnt[i]>n&&pnt[i]<t)
{
ans[pnt[i^1]][pnt[i]-n]=flow[i^1];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
printf("%d%c",ans[i][j]+1,j==m?'\n':' ');
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&row[i]);
for(int i=1;i<=m;i++)
scanf("%d",&col[i]);
printf("Matrix %d\n",cas++);
Build();
solve();
if(T)
printf("\n");
}
return 0;
}