326. Perspective
Memory limit: 65536 kilobytes
output: standard
Breaking news! A Russian billionaire has bought a yet undisclosed NBA team. He's planning to invest huge effort and money into making that team the best. And in fact he's been very specific about the expected result: the first place.
Being his advisor, you need to determine whether it's possible for your team to finish first in its division or not.
More formally, the NBA regular season is organized as follows: all teams play some games, in each game one team wins and one team loses. Teams are grouped into divisions, some games are between the teams in the same division, and some are between the teams in different divisions.
Given the current score and the total number of remaining games for each team of your division, and the number of remaining games between each pair of teams in your division, determine if it's possible for your team to score at least as much wins as any other team in your division.
The first line of input contains N (2 ≤ N ≤ 20) — the number of teams in your division. They are numbered from 1 to N, your team has number 1.
The second line of input contains N integers w1, w2,..., wN, where wi is the total number of games that ith team has won to the moment.
The third line of input contains N integers r1, r2,..., rN, where ri is the total number of remaining games for the ith team (including the games inside the division).
The next N lines contain N integers each. The jth integer in the ith line of those contains aij — the number of games remaining between teams i and j. It is always true that aij=aji and aii=0, for all i ai1 + ai2 +... + aiN ≤ ri.
All the numbers in input are non-negative and don't exceed 10/,000.
On the only line of output, print "
YES
" (without quotes) if it's possible for the team 1 to score at least as much wins as any other team of its division, and "
NO
" (without quotes) otherwise.
sample input | sample output |
3 1 2 2 1 1 1 0 0 0 0 0 0 0 0 0 | YES |
sample input | sample output |
3 1 2 2 1 1 1 0 0 0 0 0 1 0 1 0 | NO |
经典的构图
首先是比赛,篮球比赛,两个队伍参加,那么必然就只有一个队获胜,这是显而易见的。
题目给我们了每个队的已获胜场数,还需要打的比赛场数,
那么首先两个贪心是比较简单就能判断
1。首先是一队还有进行的比赛全部获胜,那么胜利场数就是a[1]+b[1]
2。其他队伍跟其他赛区的队伍比赛全是输球,跟一号队伍比赛的话也是输球
那么我们现在就可以判断剩下的场数里,能不能构造一个解,使满足在同一个赛区,其他队伍的胜利场数都小于等于1队
由于出现比赛和队伍,很容易想到二分图
由于两个队之间可能进行多场比赛,所以用多重匹配就太不划算了
自然就是最大流
那么怎么构图呢?这个构图方式很简单
左边是队伍,右边是比赛
除了1队以外,源点向所有其他队伍连边,边长为a[1]+b[1]-a[i],这就是其他队伍和一队的场次差距,也就是1队想获胜的容忍程度
再者,由于一场比赛只有一个胜者,那么当i,j队有比赛的时候,那么i,j向比赛Ci,j连边,边长即为比赛场次或者无穷大,比赛Ci,j向汇点连边,边长为比赛场次,这样就可以保证其他队伍赢得比赛场次。
这样子做最大流,当所得的流==SUM(所有比赛连向汇点的总场次和),就是我们能构造满足题意的解了。
为什么说所有P指向T的弧都满流就是YES的?
假设某条P指向T的弧不满流,则S指向I和S指向J的弧已经满流,但是还比赛还没有打完,不管剩下的比赛谁赢都将比1号球队的胜利场次多。所以若所有P指向T的弧都满流,则输出YES,否则输出NO。
#include<cstdio>
#include<cstring>
const int N=2*(21+10+21*21);
const int E=21+21*21;
const int INF=0x7fffffff;
int a[21],b[21],map[21][21];
int head[N];
struct EDGE
{
int v,next,w;
} edge[E*100];
int cnt,n,s,t;
void addedge(int u,int v,int w)
{
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].v=u;
edge[cnt].w=0;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int sap()
{
int pre[N],cur[N],dist[N],gap[N];
int flow=0,aug=INF,u;
bool flag;
for(int i=0; i<n; i++)
{
cur[i]=head[i];
gap[i]=dist[i]=0;
}
gap[s]=n;
u=pre[s]=s;
while(dist[s]<n)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dist[u]==dist[v]+1)
{
flag=1;
if(edge[j].w<aug) aug=edge[j].w;
pre[v]=u;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].w-=aug;
edge[cur[u]^1].w+=aug;
}
aug=INF;
}
break;
}
}
if(flag) continue;
int mindis=n;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if(edge[j].w>0&&dist[v]<mindis)
{
mindis=dist[v];
cur[u]=j;
}
}
if((--gap[dist[u]])==0) break;
gap[dist[u]=mindis+1]++;
u=pre[u];
}
return flow;
}
int main()
{
scanf("%d",&n);
s=0;
t=n*n+n+1;
cnt=0;
memset(head,-1,sizeof(head));
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
for(int i=1; i<=n; i++) scanf("%d",&b[i]);
int rsum=a[1]+b[1];
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d",&map[i][j]);
bool flag=true;
for(int i=2; i<=n; i++)
if(a[i]>rsum)
{
printf("NO/n");
flag=false;
break;
}
bool f1=true;
for(int i=2;i<=n;i++)
if(a[i]+b[i]>rsum) f1=false;
if(f1)
{
printf("YES/n");
flag=false;
}
if(flag)
{
int sum=0;
for(int i=2; i<=n; i++) addedge(0,i,rsum-a[i]); //0-->2...n
for(int i=2; i<=n; i++)
for(int j=i+1; j<=n; j++)
if(map[i][j]>0)
{
addedge(i,i*n+j,map[i][j]);
addedge(j,i*n+j,map[i][j]);
addedge(i*n+j,n*n+n+1,map[i][j]);
sum+=map[i][j];
}
n=n*n+n+2;
if(sum==sap()) printf("YES/n");
else printf("NO/n");
}
return 0;
}