数的加减都是从一个点到另一个点,内部总量是平衡固定的,这就跟流量是一样的。因此用网络流建模。这种类型的网络流主要就是搞清楚哪些状态和哪些状态保持平衡。
初始状态是a[i]用i点表示,最终状态是b[i]用n+i点表示。用流量表示数值,从源点向i连接容量为a[i]的边,n+i向汇点连接容量为b[i]的边。由初始状态向最终状态转移,存在(u,v)边,则由点u可以流入到点n+v,反过来v,n+u也一样。
然后判断是不是满流(表示数值在给定条件下全部转移成功,每个初始状态的数都分配给了最终状态)就可以了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=210;
struct Edge
{
int v,cap,flow, nxt;
};
int n,m, N;
int first[maxn],tot;
Edge edge[maxn*maxn*2];
void addedge(int u, int v, int cap)
{
edge[tot]=Edge{v,cap, 0, first[u]};
first[u]=tot++;
edge[tot]=Edge{u,0,0,first[v]};
first[v]=tot++;
}
int a[maxn],b[maxn];
int sum1,sum2;
void init()
{
tot=0;
memset(first, -1, sizeof(first));
sum1=sum2=0;
for(int i=1; i<=n; i++)
scanf("%d", a+i);
for(int i=1; i<=n; i++)
scanf("%d", b+i);
int s=0, t=2*n+1;
N=t+1;
for(int i=1; i<=n; i++){
sum1+=a[i];
sum2+=b[i];
addedge(s, i, a[i]);
addedge(n+i,t, b[i]);
addedge(i, n+i, inf);
}
for(int i=0; i<m; i++){
int u,v;
scanf("%d%d", &u, &v);
addedge(u,n+v, inf);
addedge(v,n+u, inf);
}
}
int cur[maxn],dep[maxn],gap[maxn],pre[maxn];
int sap(int st, int ed, int N)
{
memset(dep, 0, sizeof(dep));
memset(gap, 0, sizeof(gap));
memcpy(cur, first, sizeof(first));
int u=st, ret=0;
gap[0]=N;
pre[u]=-1;
while(dep[st]<N){
if(u==ed){
int mini=inf;
for(int i=pre[u]; i!=-1; i=pre[edge[i^1].v])
mini=min(mini, edge[i].cap-edge[i].flow);
for(int i=pre[u]; i!=-1; i=pre[edge[i^1].v]){
edge[i].flow+=mini;
edge[i^1].flow-=mini;
}
ret+=mini;
u=st;
continue;
}
bool flag=false;
for(int i=cur[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v;
if(dep[u]==dep[v]+1 &&edge[i].cap-edge[i].flow>0){
flag=true;
cur[u]=pre[v]=i;
u=v;
break;
}
}
if(flag) continue;
int mini=N;
for(int i=first[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v;
if(dep[v]<mini && edge[i].cap-edge[i].flow>0){
mini=dep[v];
cur[u]=i;
}
}
gap[dep[u]]--;
if(!gap[dep[u]]) return ret;
dep[u]=mini+1;
gap[dep[u]]++;
if(u!=st)
u=edge[pre[u]^1].v;
}
return ret;
}
int ans[maxn][maxn];
int main()
{
while(cin>>n>>m){
init();
int res=sap(0, 2*n+1, N);
if(res==sum1 && sum1==sum2){
puts("YES");
for(int u=1 ; u<=n; u++){
for(int i=first[u]; i!=-1; i=edge[i].nxt){
int v=edge[i].v;
if(edge[i].cap){
ans[u][v-n]=edge[i].flow;
}
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<n; j++)
printf("%d ", ans[i][j]);
printf("%d\n", ans[i][n]);
}
}
else puts("NO");
}
return 0;
}