1. 程式人生 > >【WOJ 124】Football Coach

【WOJ 124】Football Coach

【題目】

傳送門

Description

It is not an easy job to be a coach of a football team. The season is almost over, only a few matches are left to play. All of sudden the team manager comes to you and tells you bad news: the main sponsor of your club is not happy with your results and decided to stop sponsoring your team, which probably means the end of your club. The sponsor’s decision is final and there is no way to change it unless… unless your team miraculously wins the league.

The manager left you in deep thought. If you increase the number of practices and offer players a generous bonus for each match, you may be able to win all the remaining matches. Is that enough? You also have to make sure that teams with many points lose against teams with few points so that in the end, your team will have more points than any other team. You know some of the referees and can bribe them to manipulate the result of each match. But first you need to figure out how to manipulate the results and whether it is possible at all.

There are N teams numbered 1 through N, your team has the number N. The current number of points of each team and the list of remaining matches are given. Your task is to find out whether it is possible to manipulate each remaining match so that the team N will finish with strictly more points than any other team. If it is possible, output “YES”, otherwise, output “NO”. In every match, the winning team gets 2 points, the losing team gets 0. If the match ends with a draw, both teams get 1 point.

Input

There will be multiple test cases. Each test case has the following form: The first line contains two numbers N(1 <= N <= 100) and M(0 <= M <=1000). The next line contains N numbers separated by spaces giving the current number of points of teams 1, 2, …, N respectively. Thefollowing M lines describe the remaining matches. Each line corresponds to one match and contains two numbers a and b (a not equal to b, 1 <=a,b <= N) identifying the teams that will play in the given match. There is a blank line after each test case.

Output

For each test case, output “YES” or “NO” to denote whether it’s possible to manipulate the remaining matches so that the team N would win the league.

Sample Input

5 8 2 1 0 0 1 1 2 3 4 2 3 4 5 3 1 2 4 1 4 3 5 5 4 4 4 1 0 3 1 3 2 3 3 4 4 5

Sample Output

YES NO

Hint

The problem is so hard that even I have told you the method here is “maximum network flow”, you can’t solve it. You can have a try, but don’t waste too much time here if you are not perfect at modeling a network.

【分析】

大致題意:給出 nn 個球隊,每個球隊有一個初始分數,再給出 mm 場比賽,每次比賽給出兩個參賽的球隊。每場比賽,贏的隊伍得兩分,平局兩隊各得一分,輸的得零分。現在你可以決定每場比賽的勝負,問是否有一種方案,使得最後第 nn 個球隊的分數最高。

最大流板題

如果一個比賽中出現了 nn,那我們肯定貪心讓 nn 贏,讓 nn 得 2 分;不然的話我們相當於是在兩個隊伍中分配這 2 分,那就變成了一道最大匹配的題

還是細講一下連邊:

  1. 連邊的順序是"源點—比賽—球隊—匯點"
  2. 從源點向每場比賽連一條容量為 2 的邊,表示這場比賽總共有 2 分可以分配
  3. 從每場比賽向參賽的球隊分別連一條容量為 2 的邊,表示分配這 2 分
  4. 從每個球隊向匯點連一條 scorenscorei1score_n-score_i-1 的邊,表示它最多分配這麼多分(不然就超過 nn 的分數)
  5. 最後看跑出來最大流是否能匹配完所有比賽即可

【程式碼】

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1005
#define M 10005
#define inf (1ll<<31ll)-1
using namespace std;
int n,m,s,t,num;
int v[M],w[M],nxt[M];
int d[N],f[N],first[N],score[N];
void add(int x,int y,int z)
{
	num++;
	nxt[num]=first[x];
	first[x]=num;
	v[num]=y;
	w[num]=z;
}
bool bfs()
{
	int x,y,i,j;
	memset(d,-1,sizeof(d));
	memcpy(f,first,sizeof(f));
	queue<int>q;d[s]=0;q.push(s);
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(i=first[x];i;i=nxt[i])
		{
			y=v[i];
			if(w[i]&&d[y]==-1)
			{
				d[y]=d[x]+1;
				if(y==t)
				  return true;
				q.push(y);
			}
		}
	}
	return false;
}
int dinic(int now,int flow)
{
	if(now==t)  return flow;
	int x,delta,ans=0;
	for(int &i=f[now];i;i=nxt[i])
	{
		x=v[i];
		if(w[i]&&d[x]==d[now]+1)
		{
			delta=dinic(x,min(flow,w[i]));
			w[i]-=delta,w[i^1]+=delta;
			flow-=delta,ans+=delta;
			if(!flow)  return ans;
		}
	}
	return ans;
}
int main()
{
	int x,y,i,j,ans=0;
	while(~scanf("%d%d",&n,&m))
	{
		num=1;
		memset(first,0,sizeof(first));
		int match=0;
		ans=0,s=0,t=m+n+1;
		for(i=1;i<=n;++i)
		  scanf("%d",&score[i]);
		for(i=1;i<=m;++i)
		{
			scanf("%d%d",&x,&y);
			if(x==n||y==n)
			  score[n]+=2;
			else
			{
				match++;
				add(s,i,2),add(i,s,0);
				add(i,m+x,2),add(m+x,i,0);
				add(i,m+y,2),add(m+y,i,0);
			}
		}
		for(i=1;i<n;++i)
		{
			if(score[i]>score[n])
			{
				printf("NO\n");
				break;
			}
			add(m+i,t,score[n]-score[i]-1);
			add(t,m+i,0);
		}
		if(i<n)  continue;
		while(bfs())
		  ans+=dinic(s,inf);
		if(ans/2<match)  printf("NO\n");
		else  printf("YES\n");
	}
	return 0;
}