WHU1124 Football Match

http://acm.whu.edu.cn/learn/problem/detail?problem_id=1124

题目大意:有N支球队,你们是第N支。每个队伍已经有一些分数了,接下来还有M场比赛。每场比赛有两支参赛队伍,赢得队得2分,输的队不得分,平局各得一分。现在你可以操控所有比赛的胜负。问你最后你们队是否能成为第一名(分数严格大于其他所有队分数)

分析:第一道用满流来解决问题的题。首先明确我们能做两种伎俩。一是我们参与的比赛肯定选我们赢。然后我们不参与的比赛就通过压制分数高的队让他们分数没有我们高,这个trick比较难不是贪心能解决的。首先对于有N参加的比赛,肯定是赢了最好,暂时先不考虑其他的比赛,这是如果各队的积分有大于或等于第N队的,那么肯定是输出NO的。接下来考虑其他的比赛,对于任意队伍i而言,得分是不等等于或者超过score[N]的,因此可以将i和汇点连一条容量为score[N]-score[i]-1的边,由于比赛的总积分是2,自然谁参加哪场比赛就对应连若干容量为2的边即可,这样做最大流,如果最后能够满流就说明所有的比赛都能安排妥当。

建边方案:

1)将源点拆成若干个,分别对应每场比赛,如a和b比一场,则S--2-->S',S'--2-->a,S'--2-->b;

2)不拆点,若a和b比一场,则S--2-->a,a--2(注意不能是inf)-->b;(反例:如a和b赛,b和c赛,则存在a:b:c=0:0:4的结果。)

贴代码(1):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int maxn=1110,maxm=7000,inf=0x7fffffff;
int n,m,a,b,s,t,maxflow,tot=1,flag,p,score[maxn],head[maxn],cur[maxn],h[maxn];
queue<int> q;
struct node{
    int go,next,v;
}e[maxm];
inline int read(){
    int x=0;char ch=getchar();
    while (ch>'9' || ch<'0')ch=getchar();
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
inline void addedge(int x,int y,int v){
    e[++tot]=(node){y,head[x],v};head[x]=tot;
    e[++tot]=(node){x,head[y],0};head[y]=tot;
}
bool bfs(){
    for (int i=1;i<=t;i++) h[i]=-1;
    q.push(s);h[s]=0;
    while (!q.empty()){
        int x=q.front();q.pop();
        for (int i=head[x];i;i=e[i].next){
            if (e[i].v && h[e[i].go]==-1){
                q.push(e[i].go);
                h[e[i].go]=h[x]+1;
            }
        }
    }
    return h[t]!=-1;
}
int dfs(int x,int f){
    if (x==t) return f;
    int tmp,used=0;
    for (int i=cur[x];i;i=e[i].next){
        if (e[i].v && h[e[i].go]==h[x]+1){
            tmp=dfs(e[i].go,min(e[i].v,f-used));
            e[i].v-=tmp;if (e[i].v) cur[x]=i;
            e[i^1].v+=tmp;used+=tmp;
            if (used==f) return f;
        }
    }
    if (!used) h[x]=-1;
    return used;
}
void dinic(){
    maxflow=0;
    while (bfs()){
        for (int i=1;i<=t;i++) cur[i]=head[i];
        maxflow+=dfs(s,inf);
    }
}
int main(){
    while (scanf("%d%d",&n,&m)!=EOF){
        for (int i=1;i<=t;i++) head[i]=0;
        tot=1;s=n+1;t=1105;p=0;flag=0;
        for (int i=1;i<=n;i++) score[i]=read();
        for (int i=1;i<=m;i++){
            a=read();b=read();
            if (a==n || b==n) score[n]+=2;
            else{
                p+=2;
                addedge(s,i+s,2);
                addedge(i+s,a,2);
                addedge(i+s,b,2);
            }
        }
        for (int i=1;i<n;i++){
            if (score[i]>=score[n]) {flag=1;printf("NO\n");break;}
            else if (score[n]-1-score[i]) addedge(i,t,score[n]-1-score[i]);
        }
        if (flag) continue;
        dinic();
        if (maxflow==p) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
View Code

贴代码(2):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int maxn=1110,maxm=7000,inf=0x7fffffff;
int n,m,a,b,s,t,maxflow,tot=1,flag,p,score[maxn],head[maxn],cur[maxn],h[maxn];
queue<int> q;
struct node{
    int go,next,v;
}e[maxm];
inline int read(){
    int x=0;char ch=getchar();
    while (ch>'9' || ch<'0')ch=getchar();
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x;
}
inline void addedge(int x,int y,int v){
    e[++tot]=(node){y,head[x],v};head[x]=tot;
    e[++tot]=(node){x,head[y],0};head[y]=tot;
}
bool bfs(){
    for (int i=1;i<=t;i++) h[i]=-1;
    q.push(s);h[s]=0;
    while (!q.empty()){
        int x=q.front();q.pop();
        for (int i=head[x];i;i=e[i].next){
            if (e[i].v && h[e[i].go]==-1){
                q.push(e[i].go);
                h[e[i].go]=h[x]+1;
            }
        }
    }
    return h[t]!=-1;
}
int dfs(int x,int f){
    if (x==t) return f;
    int tmp,used=0;
    for (int i=cur[x];i;i=e[i].next){
        if (e[i].v && h[e[i].go]==h[x]+1){
            tmp=dfs(e[i].go,min(e[i].v,f-used));
            e[i].v-=tmp;if (e[i].v) cur[x]=i;
            e[i^1].v+=tmp;used+=tmp;
            if (used==f) return f;
        }
    }
    if (!used) h[x]=-1;
    return used;
}
void dinic(){
    maxflow=0;
    while (bfs()){
        for (int i=1;i<=t;i++) cur[i]=head[i];
        maxflow+=dfs(s,inf);
    }
}
int main(){
    while (scanf("%d%d",&n,&m)!=EOF){
        for (int i=1;i<=t;i++) head[i]=0;
        tot=1;s=n+1;t=1105;p=0;flag=0;
        for (int i=1;i<=n;i++) score[i]=read();
        for (int i=1;i<=m;i++){
            a=read();b=read();
            if (a==n || b==n) score[n]+=2;
            else{
                p+=2;
                addedge(s,a,2);
                addedge(a,b,2);
            }
        }
        for (int i=1;i<n;i++){
            if (score[i]>=score[n]) {flag=1;printf("NO\n");break;}
            else if (score[n]-1-score[i]) addedge(i,t,score[n]-1-score[i]);
        }
        if (flag) continue;
        dinic();
        if (maxflow==p) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
View Code

转载于:https://www.cnblogs.com/fqqq/p/5228033.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值