zoj3348 网络流

Schedule

Time Limit: 1 Second Memory Limit: 32768 KB

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


题意:有n个人,已知前面m场比赛的最终情况和后面将比的p场比赛,问最后DD有没有可能赢

一开始,我以为先对每个人计数,然后后面p场比赛,只要DD都赢,其他比赛只要得分小的+1,后来发现都是相等的时候,每个决策都可能跟后面结果有关,顿时没思路,看了题解才知道是网络流

思路:

前面先把DDhash一下,保存在第0位。然后对前面m场比赛进行哈希跟计算每个人赢了几场

然后是接下来的p场比赛。先让hash值较小的赢,并且记录它赢了对方几场

最后是建图了,首先设源点为s(我用了0表示,是因为DD这个点不需要用到,所以就拿来用),汇点为e(总结点+1)

总共需要三种边:

①edge(s,i,cou[i]):即s到除DD外的每个点都有一条流量为i胜了几场的边

②edge(i,e,cou[0]-1):即除DD外的每个点到汇点都有一条流量为DD最多胜几场-1,保证其他人赢的没DD多

③edge(i,j,E[i][j]):之前我们假设让hash值小的赢,所以我们让他们间有一条边可以流过去

把除DD外,所有人胜的场次加起来为sum,当s到e的最大流等于sum时,则剩下的p场比赛可以把他们每个人胜的情况分散,使得他们都不超过DD胜的次数。否则,比sum小,表示一定存在至少一条,它被“截流”了。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 55;
const int INF = 0x3f3f3f3f;
struct Node
{
    int to;//终点
    int cap; //容量
    int rev;  //反向边
};

vector<Node> v[N];
bool used[N];
void add_Node(int from,int to,int cap)  //重边情况不影响
{
    v[from].push_back((Node){to,cap,v[to].size()});
    v[to].push_back((Node){from,0,v[from].size()-1});
}

int dfs(int s,int t,int f)
{
    if(s==t)
        return f;
    used[s]=true;
    for(int i=0;i<v[s].size();i++)
    {
        Node &tmp = v[s][i];  //注意
        if(used[tmp.to]==false && tmp.cap>0)
        {
            int d=dfs(tmp.to,t,min(f,tmp.cap));
            if(d>0)
            {
                tmp.cap-=d;
                v[tmp.to][tmp.rev].cap+=d;
                return d;
            }
        }
    }
    return 0;
}

int max_flow(int s,int t)
{
    int flow=0;
    for(;;){
        memset(used,false,sizeof(used));
        int f=dfs(s,t,INF);
        if(f==0)
            return flow;
        flow+=f;
    }
}
int cou[55];
int E[55][55];
map<string,int> mp;
void init(int n){//每个样例需先初始化边集数组 
	for(int i=0;i<n;i++){
		v[i].clear();
	}
	mp.clear();
	mp["DD"]=0;
	memset(cou,0,sizeof(cou));
	memset(E,0,sizeof(E));
}

int main()
{
	int n,m,p,idx;
	int x,y;
	string a,b;
	char str[10];
	while(~scanf("%d%d",&n,&m)){
		init(n),idx=0;
		while(m--){
			cin>>a>>b>>str;
			if(mp.count(a)==0) mp[a]=++idx;
			if(mp.count(b)==0) mp[b]=++idx;
			if(str[0]=='w') cou[mp[a]]++;
			else cou[mp[b]]++;
		}
		scanf("%d",&p);
		while(p--){
			cin>>a>>b;
			if(mp.count(a)) x=mp[a];
			else x=mp[a]=++idx;
			if(mp.count(b)) y=mp[b];
			else y=mp[b]=++idx;
			if(y<x) x=x^y,y=x^y,x=x^y;
			cou[x]++;
			E[x][y]++;
		}
		if(cou[0]==0){
			if(n==1) printf("Yes\n");
			else printf("No\n");
			continue;
		}
		int s=0;
		int e=idx+1;
		int up=cou[0]-1;
		int sum=0;
		for(int i=1;i<=idx;i++){
			sum+=cou[i];
			add_Node(s,i,cou[i]);
			add_Node(i,e,up);
			for(int j=i+1;j<=idx;j++)
				if(E[i][j])
					add_Node(i,j,E[i][j]);
		}
		int ans=max_flow(s,e);
		if(ans==sum) printf("Yes\n");
		else printf("No\n");
		
	}
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值