【 zoj 3348 】Schedule 【网络流经典建图】

DD enters the top-level pingpong match! As the game going on, he wonders if there is possibility for him to get the champion(excluding joint champions). Now provide you the results of previous matches, and the details of rest matches. You have to judge it.

Input
There are several test cases. You should process to the end of input.

For each test case. the first line contain two integers n (1 <= n <= 50) and m(0 <= m <= 1000), n indicates the number of players. m indicates the matches have ended.

Then for the following m lines, each line has the format: “Player1 Player2 Result”. Player1 and Player2 are the names of the two players, and Result could only be “win” or “lose”.

In the next line there is another integer p (0 <= p <= 5000), indicates the matches that will start later.

Then for the following p lines, each line has the format: “Player1 Player2”, which means Player1 and Player2 will start a match.

We ensure there is a player named “DD”. The length of each player name is no longer than 10.

Output
You should only output “Yes” or “No” for each case, which means if DD has the possibility to be the champion.

Sample Input
3 2
DD winsty win
DD owen lose
2
winsty owen
DD owen
3 3
DD winsty win
DD owen lose
winsty owen lose
2
owen winsty
owen DD

Sample Output
Yes
No

分析 :假设剩下的q场比赛中DD参加了a场,在之前的M场比赛中胜利了b场,我们可以认为这a场都是DD胜利(当然要用临界情况判断,想一下,若下面全赢DD还不是冠军 就肯定没有希望了),这样DD胜利了a+b场。这样问题转化为能否将剩下的q-a场比赛(也就是剩下的P场比赛中DD没有参与的比赛)的胜利分配给除了DD以外的所有n-1人,使得除DD外任意一人的胜场数都小于DD的胜场数。
建图:设源点S,汇点T,把每场比赛虚拟成一个节点。
一:从S向 所有q-a场比赛 引一条容量为1的边;
二:因为每场比赛只有一个胜者,所以每场比赛要向参加比赛的两个选手连边,容量为1,代表这个比赛的胜利只能由两人中的一人获得。
三:除DD外每个人向T连边,容量为a + b - 1-win[i] ,代表每个人的胜利次数不能超过DD胜利的次数。
然后对这个图求最大流,如果最大流小于q-a则代表无法将q-a场比赛的胜利分配给n-1人,则输出NO。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int MAXN = 1e4;
const int MAXM = 1e6;
const int inf=0x3f3f3f3f;
struct Edge {
    int from,to,cap,flow,nexts;
}edge[MAXM];
int head[MAXN],top;
int n,m,q;
map<string,int>mp;
int score[MAXN];
int S,T;
void init(){
    memset(head,-1,sizeof(head));
    top=0;
}
void addedge(int a,int b,int c){
    Edge e={a,b,c,0,head[a]};
    edge[top]=e;head[a]=top++;

    Edge ee={b,a,0,0,head[b]};
    edge[top]=ee;head[b]=top++;
}
int num; // DD在将要开始的比赛中参加的场数
int flage; //是否赢
void getmap(){
    S=0;
    mp.clear();
    memset(score,0,sizeof(score));
    mp["DD"]=1;string a,b,c;
    int ge=2; 
    while(m--){
        cin>>a>>b>>c;
        if(!mp[a]) mp[a]=ge++;
        if(!mp[b]) mp[b]=ge++;
            if(c=="win") score[mp[a]]++; 
            else if(c=="lose") score[mp[b]]++;
    }
    scanf("%d",&q);
    S=0;T=q+n+1;
    int DDscore=score[1]; num=0;
    for(int i=1;i<=q;i++){
        cin>>a>>b;
        if(!mp[a]) mp[a]=ge++;
        if(!mp[b]) mp[b]=ge++;
        if(a=="DD"||b=="DD") { DDscore++; continue;}
        num++;
        addedge(S,i+n,1);
        addedge(i+n,mp[a],1);
        addedge(i+n,mp[b],1);
    }
    flag=1;// 这中情况要特判一下,因为用最大流无法解决这种情况
    for(int i=2;i<ge;i++) 
        if( DDscore<=score[i]) {
            flag=0;return ;
        }
        for(int i=2;i<ge;i++)
            addedge(i,T,DDscore-1-score[i]);//DD总赢的场数-1-每个人已经赢的场数
}
int vis[MAXN],dis[MAXN];
int cur[MAXN];
bool bfs(int st,int ed){
    memset(vis,0,sizeof(vis));
    queue<int>Q; Q.push(st);
    vis[st]=1;dis[st]=1;
    while(!Q.empty()){
        int now=Q.front();Q.pop();
        for(int i=head[now];i!=-1;i=edge[i].nexts){
            Edge e=edge[i];
            if(!vis[e.to]&&e.cap-e.flow>0){
                vis[e.to]=1;
                dis[e.to]=dis[now]+1;
                if(e.to==ed)  return 1;
                Q.push(e.to);
            }
        }
    }
    return 0;
}
int dfs(int now,int a,int ed){
    if(now==ed||a==0) return a;
    int flow=0,f;
    for(int& i=cur[now];i!=-1;i=edge[i].nexts){
        Edge &e=edge[i];
        if(dis[e.to]==dis[now]+1&&(f=dfs(e.to,min(a,e.cap-e.flow),ed))>0){
            e.flow+=f;
            flow+=f;
            edge[i^1].flow-=f;
            a-=f;
            if(a==0) break;
        }
    }
    return flow;
}
int max_flow(int st,int ed){
    int flow=0;
    while(bfs(st,ed)){
        memcpy(cur,head,sizeof(head));
        flow+=dfs(st,inf,ed);
    }
    return flow;
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        getmap();
        if(!flag){ puts("No"); continue;}
        if(max_flow(S,T)>=num) puts("Yes");
        else puts("No");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值