woj1124 贪心+dinic

Problem 1124 - Football Coach
Time Limit: 2000MS    Memory Limit: 65536KB   
Total Submit: 299   Accepted: 137   Special Judge: No
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. The 
following 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.


#include<cstdio>
#include<iostream>
#include<cstring>
#define Maxn 1110
using namespace std;

int score[Maxn];
const int inf=0x3f3f3f3f;
struct line{
    int to,next,cap;
}p[Maxn*Maxn*2];
int head[Maxn];
int q[Maxn];
int d[Maxn];
int tot;
int src,t;
int n,m;
void addedge(int a,int b,int c){
    p[tot].to=b;
    p[tot].next=head[a];
    p[tot].cap=c;
    head[a]=tot++;
}
void insert(int a,int b,int c){
    addedge(a,b,c);
    addedge(b,a,0);
}
bool bfs(){
    memset(d,-1,sizeof d);
    int s=0,e=-1;
    q[++e]=src;
    d[src]=0;
    while(s<=e){
        int u=q[s++];
        for(int i=head[u];i!=-1;i=p[i].next){
            int v=p[i].to;
            if(d[v]==-1&&p[i].cap){
                d[v]=d[u]+1;
                q[++e]=v;
            }
        }
    }
    return d[t]!=-1;
}
int dfs(int u,int alpha){
    if(u==t) return alpha;
    int w,used=0;
    for(int i=head[u];i!=-1&&used<alpha;i=p[i].next){
        int v=p[i].to;
        if(p[i].cap&&d[v]==d[u]+1){
            w=dfs(v,min(alpha-used,p[i].cap));
            used+=w;
            p[i].cap-=w;
            p[i^1].cap+=w;
        }
    }
    if(!used) d[u]=-1;
    return used;
}
int dinic(){
    int ans=0;
    src=0,t=m+n+1;
    while(bfs())
        ans+=dfs(src,inf);
    return ans;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)
            scanf("%d",score+i);
        int res=0;
        tot=0;
        memset(head,-1,sizeof head);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&a,&b);
            if(a>b) swap(a,b);
            if(b==n) score[n]+=2;
            else{
                res++;
                insert(0,i,2);
                insert(i,m+a,2);
                insert(i,m+b,2);
            }
        }
        bool flag=true;
        for(int i=1;i<n;i++)
            if(score[i]>=score[n]){
                flag=false;
                break;
            }
        if(!flag) puts("NO");
        else{
            for(int i=1;i<n;i++)
                insert(m+i,m+n+1,score[n]-1-score[i]);
            if(dinic()==res*2) puts("YES");
            else puts("NO");
        }
    }
	return 0;
}

题意:有n个选手,第i个分数为score[i],现在还有m场比赛结果还没定,但比赛双方已定,已知赢家获2分,输家获0分,平手双方各获1分。问是否存在一种方案,使得第n名选手分数都大于其余n-1名选手。

首先来一点贪心:凡是第n名选手与其他选手参加的比赛,都让第n名选手获胜。然后忽略其余选手比赛,先判断一下目前前n-1名选手分数是否存在大于等于第n选手的,因为接下来比赛没有第n名选手了,所以第n名选手目前分数已经是最高的了,而其他选手不管怎么比赛分数不会减,只可能不变或增加,所以如果目前前n-1名选手的分数大于等于第n选手,那么这些选手最后的成绩也将大于等于第n选手,这里就可以判断无解的情况。

还无法判断:接下来就是其余选手之间的比赛了,该如何分配分数呢?这显然就得用网络流了。

观察每场比赛(排除有第n名选手参加的,因为之前已经算作第n名选手赢了)会增加分数为2,不管是平手(1 1)还是一赢一输(2 0),因此由源点连向每场比赛一条边权为2的边,对于第i场比赛,参加选手u,v,则由i连向u和v,边权均为2,这个表示流入i为2的流量,可以自由分配给u和v,可以有很多情况(0,0),(0,2),(0,1),(1,1)。。。这里(0,0)和(0,1)是不会出现的,因为我们最后要跑这个网络,并希望得到满流,所以像(0,0)和(0,1)这两种情况,结果不满流,就是无解情况。因此对于(0,2),(2,0),(1,1)才有可能满流,这也正是我们想要的,也恰好符合题意三种比赛结果,这真是太巧妙的联系。

最后,我们将前n-1个选手连向汇点,第i名选手边权为score[n]-1-score[i],这个也就限制这名选手最多只能赢这么多分数,否则无解。最后一遍最大流,如果满流就是说明有解。

太神奇了,所有无解的情况全部合成了非满流的情况。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值