题意:对于一个R行C列的正整数矩阵,设Ai为前i行所有元素之和,Bi为前i列所有元素之和。已知R,C和数组A和B,找一个满足的条件的矩阵,矩阵中的元素必须是1~20之间的正整数,输入保证有解。
题意:首先根据Ai和Bi计算出第i行的元素之和Ai’和第j列的元素之和Bj‘。如果把矩阵里的每个数都减1,则每个Ai’会减少C,而每个Bi‘会减少R。这样一来,每个元素的范围变成了0~19,这样在求解网络流中就不用下限计算了。
建立二分图,每行对应一个X结点,每列对应一个Y结点,然后增加源点s和汇点t,对于每个结点Xi,从s到Xi连一条弧,容量为Ai'-C。从Yi到t连一条狐,容量为Bi'-R。对于每对结点(Xi,Yj),从Xi到Yj连一条弧,容量为19。接下来求s-t的最大流,如果所有s出发到达t都满载,说明问题有解,由于题目保证有解,所以直接输出,结点Xi->Yj的流量就是格子(i,j)减1之后的值。
附上代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=50+5;
const int inf=0x3f3f3f3f;
struct Edge{
int from,to,cap,flow;
Edge(int _from,int _to,int _cap,int _flow):from(_from),to(_to),cap(_cap),flow(_flow){}
};
struct edmondskarp{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int a[maxn];
int p[maxn];
void init(int n){
for(int i=0;i<n;i++){
G[i].clear();
}
edges.clear();
}
void addedge(int from,int to,int cap){
edges.push_back(Edge(from,to,cap,0));
edges.push_back(Edge(to,from,0,0));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
int maxflow(int s,int t){
int flow=0;
for(;;){
memset(a,0,sizeof(a));
queue<int>Q;
Q.push(s);
a[s]=inf;
while(!Q.empty()){
int x=Q.front();Q.pop();
for(int i=0;i<G[x].size();i++){
Edge &e=edges[G[x][i]];
if(!a[e.to]&&e.cap>e.flow){
p[e.to]=G[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
Q.push(e.to);
}
}
if(a[t]){
break;
}
}
if(!a[t]){
break;
}
for(int u=t;u!=s;u=edges[p[u]].from){
edges[p[u]].flow+=a[t];
edges[p[u]^1].flow-=a[t];
}
flow+=a[t];
}
return flow;
}
};
edmondskarp g;
int no[maxn][maxn];
int main()
{
int T,R,C,v;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++){
scanf("%d%d",&R,&C);
g.init(R+C+2);
int last=0;
for(int i=1;i<=R;i++){
scanf("%d",&v);
g.addedge(0,i,v-last-C);
last=v;
}
last=0;
for(int i=1;i<=C;i++){
scanf("%d",&v);
g.addedge(R+i,R+C+1,v-last-R);
last=v;
}
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
g.addedge(i,R+j,19);
no[i][j]=g.edges.size()-2;
}
}
g.maxflow(0,R+C+1);
printf("Matrix %d\n",kase);
for(int i=1;i<=R;i++){
for(int j=1;j<=C;j++){
printf("%d ",g.edges[no[i][j]].flow+1);
}
printf("\n");
}
printf("\n");
}
return 0;
}