Description
Input
Output
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 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
|
题意:NBA 某小组内有 N 支球队,小组内以及小组间已经进行了若干场比赛。现在给出这 N 支球队目前胜利的场数、还剩多少场没有比(包括小组内和小组间)以及小组内任意两支球队之间还剩多少场没有比,存在maze[i][j]中, 问能否合理安排剩下的所有比赛,使得球队 1 最后胜利的场数至少和小组内任何一支其他球队一样。 (2 <= N <= 20,0 <= x <= 10000, x 表示其他任何输入)
分析:首先,所有和球队1相关的比赛都让1赢,胜场记为win=w[1]+r[1](已经赢得加上还剩下的比赛),如果已经此时仍然有球队胜利的场数大于球队1,那不管怎么挣扎,就算让这个球队剩下的比赛全输,球队1都不可能赢了对吧。除了1的其他球队所有组间赛都让他输(组间赛的场数可求,因为告诉了r[i]和组内的剩下比赛),组内赛再说。既然约定与球队1相关的比赛都是1赢,那么剩下的比赛中与1相关的比赛就不用管了,都已经是1赢了,调整不了了,因为每个球队已经有过胜场,那么要使球队1拿第一,那么其他球队i在剩下的比赛赢场最多为win-w[i]。
现在可以开始建图了,我们把点分为几类:源点,汇点,球队(除球队1),比赛(除开和1有关的比赛)。 首先,源点向每个球队连一条边,容量为该球队最多胜场(win-w[i]),因为每个球队接下来还要打比赛,所以对于某次比赛maze[i][j](其中i!=1,j!=1),我们让i和j分别与此次比赛连边,容量都为inf,或者maze[i][j],再把此次比赛与汇点连一条边,容量为maze[i][j],每场比赛都用一个特定的数值代替就可以建图了。最后,sum记录和球队1无关的所有组内赛总数(因为我们建图全是组内赛,组间赛已经让他们输了,没必要考虑),看看跑出的最大流是否等于sum,如果等于那么可以调整让球队1 赢,因为其他球队的剩下的比赛不管输赢都正常进行了。
#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<algorithm> #define maxn 2000 #define inf 0x7fffffff using namespace std; struct edge { int from,to,cap,flow; }; vector<edge> edges; vector<int> G[maxn]; int d[maxn],cur[maxn]; bool vis[maxn]; int s,t; void init() { for(int i=0;i<maxn;i++) G[i].clear(); edges.clear(); } void add(int from,int to,int cap) { edges.push_back((edge){from,to,cap,0}); edges.push_back((edge){to,from,0,0}); int m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool bfs() { memset(vis,false,sizeof(vis)); memset(d,0,sizeof(d)); queue<int> q; q.push(s); d[s]=0,vis[s]=true; 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(!vis[e.to]&&e.cap>e.flow) { vis[e.to]=true; d[e.to]=d[x]+1; q.push(e.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int& i=cur[x];i<G[x].size();i++) { edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0) { e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int maxflow() { int flow=0; while(bfs()) { memset(cur,0,sizeof(cur)); flow+=dfs(s,inf); } return flow; } int w[30],r[30],maze[30][30]; int main() { int n; while(scanf("%d",&n)==1) { s=0,t=1000; for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<=n;i++) scanf("%d",&r[i]); int win=w[1]+r[1],sum=0,flog=1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&maze[i][j]); init(); for(int i=2;i<=n;i++) { if(win-w[i]<0)///如果某支球队已经赢得场数都大于球队1最大可能赢得场数,那么GG,怎么也不可能赢了 { flog=0; break; } add(s,i+400,win-w[i]); } if(flog==0) { puts("NO"); continue; } for(int i=2;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(maze[i][j]<=0) continue; sum+=maze[i][j];///比赛场数 add((i-1)*n+j,t,maze[i][j]);///比赛与汇点连边 add(i+400,(i-1)*n+j,maze[i][j]);///球队与比赛连边 add(j+400,(i-1)*n+j,maze[i][j]);///球队与比赛连边 } } int ans=maxflow(); if(sum==ans) puts("YES"); else puts("NO"); } return 0; }