题目大意:NBA 某小组内有 N 支球队,小组内以及小组间已经进行了若干场比赛。现在给
出这 N 支球队目前胜利的场数、还剩多少场没有比(包括小组内和小组间)以
及小组内任意两支球队之间还剩多少场没有比,问能否合理安排剩下的所有比赛,
使得球队 1 最后胜利的场数至少和小组内任何一支其他球队一样。
(2 <= N <= 20,
0 <= x <= 10000, x 表示其他任何输入)
同样,所有和球队 1 相关的比赛全让球队 1 赢,如果此
时仍有某支球队胜利的场数大于球队 1,则已经不可能满足要求。按如下方法建
图:所有小组内的比赛 i(不包括与球队 1 相关的比赛)作为一个点并加边(s, i,
num[i]),每支球队(不包括球队 1)作为一个点并加边(j, t, wins[1]-wins[i]),每场
比赛向与其关联的两支球队 u, v 连边(i, u, ∞), (i, v, ∞)。至于其他球队小组间的
比赛,直接让他们输掉就好,不用管。若最大流等于∑num[i]则可以满足要求。
ps:此类比赛的问题一般将比赛和球队作为点,源点向每个比赛的点连一条场数的边,每个比赛向参加比赛的球队连边(流量视情况而定),然后每个球队向汇点连一条边,流量即为该球队胜场的限制.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<set>
#include<vector>
#include<cmath>
#include<map>
#include<queue>
#define LL long long
using namespace std;
const LL mod=1e9+7;
const int N=1e3+5;
const int inf=0x3f3f3f3f;
struct node
{
int to,cap,next,flow;
node(){}
node(int to,int cap,int next,int flow):to(to),cap(cap),next(next),flow(flow){}
}edge[N<<2];
int tol;
int head[N],gap[N],dep[N],pre[N],cur[N];
int win[N],r[N],a[N][N];
void init()
{
tol=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w,int rw=0)
{
edge[tol]=node(v,w,head[u],0);
head[u]=tol++;
edge[tol]=node(u,rw,head[v],0);
head[v]=tol++;
}
int sap(int start,int _end,int N)
{
memset(gap,0,sizeof(gap));
memset(dep,0,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u=start;
pre[u]=-1;
gap[0]=N;
int ans=0;
while(dep[start]<N)
{
if(u==_end)
{
int Min=inf;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
for(int i=pre[u];i!=-1;i=pre[edge[i^1].to])
{
edge[i].flow+=Min;
edge[i^1].flow-=Min;
}
u=start;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u])
{
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag)
{
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-1;i=edge[i].next)
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
{
Min=dep[edge[i].to];
cur[u]=i;
}
gap[dep[u]]--;
if(!gap[dep[u]])return ans;
dep[u]=Min+1;
gap[dep[u]]++;
if(u!=start)u=edge[pre[u]^1].to;
}
return ans;
}
int main()
{
//freopen("a.txt","r",stdin);
int n;
while(~scanf("%d",&n))
{
init();
for(int i=1;i<=n;i++)scanf("%d",&win[i]);
for(int i=1;i<=n;i++)scanf("%d",&r[i]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
int temp=win[1]+r[1];
int flag=1;
for(int i=2;i<=n;i++)
if(win[i]>temp)flag=0;
if(flag==0)
{
puts("NO");continue;
}
int cnt=0,sum=0;
for(int i=2;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
cnt++;sum+=a[i][j];
addedge(0,cnt,a[i][j]);
addedge(cnt,i-1+n*(n-1)/2,inf);
addedge(cnt,j-1+n*(n-1)/2,inf);
}
}
for(int i=2;i<=n;i++)
addedge(i-1+n*(n-1)/2,n*(n+1)/2,temp-win[i]);
int ans=sap(0,n*(n+1)/2,n*(n+1)/2+1);
if(ans==sum)puts("YES");
else puts("NO");
}
return 0;
}