2016 ICPC 大连 A Wrestling Match (二分图)

题目链接Wrestling Match - HDU 5971 - Virtual Judge

Wrestling Match

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 6322    Accepted Submission(s): 2201


Problem Description
Nowadays, at least one wrestling match is held every year in our country. There are a lot of people in the game is "good player”, the rest is "bad player”. Now, Xiao Ming is referee of the wrestling match and he has a list of the matches in his hand. At the same time, he knows some people are good players,some are bad players. He believes that every game is a battle between the good and the bad player. Now he wants to know whether all the people can be divided into "good player" and "bad player".
 

Input
Input contains multiple sets of data.For each set of data,there are four numbers in the first line:N (1 ≤ N≤ 1000)、M(1 ≤M ≤ 10000)、X,Y(X+Y≤N ),in order to show the number of players(numbered 1toN ),the number of matches,the number of known "good players" and the number of known "bad players".In the next M lines,Each line has two numbersa, b(a≠b) ,said there is a game between a and b .The next line has X different numbers.Each number is known as a "good player" number.The last line contains Y different numbers.Each number represents a known "bad player" number.Data guarantees there will not be a player number is a good player and also a bad player.
 

Output
If all the people can be divided into "good players" and "bad players”, output "YES", otherwise output "NO".
 

Sample Input
  
  
5 4 0 0 1 3 1 4 3 5 4 5 5 4 1 0 1 3 1 4 3 5 4 5 2
 

Sample Output
  
  
NO YES
 

Source
 

Recommend
wange2014
 

Statistic |  Submit |  Discuss | Note

题目大意

目前有N个点,M条线。N个点状态可以为好,孬和不确定。M条线,每条线连接的两个点一定是一好一孬的。此外还预先知道了几个点的好孬装填,问你能否凭这些信息确定所有点的好孬状态。

分析

近乎赤裸的二分图染色问题。唯一的坑在于合法性的判断。对于有线连接的点,可以在“每条线连接的两个点一定是一好一孬的”的前提下随意染色。而没有线连接的点只能预知颜色,不能后天染色。

开始前定义个枚举*enum* Stat{BLACK=-1, UNKNOWN=0, WHITE=1} 表示每个点的颜色可取值:黑色,未染色,白色。

首先建图,这一过程中对题目输入中所有提到的点都打个mention标记,表示这些点要么已经有颜色,要么可以被后天染色。

然后对每个颜色已知且未被访问过的点做dfs,把与它能连通且颜色未定的点全染上色。

再然后对每个颜色未知且为访问过的点染成黑色,然后做dfs,把与它能连通且颜色未定的点全染上色。

最后合法性检验,看看是不是知道了所有点的颜色,并且每条线连着的点颜色都不冲突。

AC代码

#include <bits/stdc++.h>
using namespace std;

#define DEBUG 0
#define plog if(DEBUG) std::cout
const int MAXN=1000+5;
enum Stat{BLACK=-1, UNKNOWN=0,  WHITE=1}; // 染色状态可取值的集合:黑色,未染色,白色
vector<int> G[MAXN];
int st[MAXN];	// 每个点染色状态
bool vis[MAXN];	// 访问标记
bool legal;		// 合法性标记
bool ment[MAXN];	// 在输入阶段是否提及

void init(int n){
	for(int i=0;i<=n;i++){
		G[i].clear();
		st[i]=UNKNOWN;
		vis[i]=false;
		ment[i]=false;
	}
	legal=true;
}


void dfs(int u){
	vis[u]=true;
	for(int v:G[u]){
		if(!vis[v]){
			if(st[v]==UNKNOWN){
				st[v]=-st[u];
			}
			dfs(v);
		}
	}
}

int main(){
	ios::sync_with_stdio(0);
	int n,m,cntx,cnty;
	while(cin>>n>>m>>cntx>>cnty){
		init(n);
		for(int i=0;i<m;i++){
			int u,v;
			cin>>u>>v;
			G[u].push_back(v);
			G[v].push_back(u);
			ment[u]=ment[v]=true;
		}
		for(int i=0;i<cntx;i++){
			int x;
			cin>>x;
			ment[x]=true;
			st[x]=WHITE;
		}
		for(int i=0;i<cnty;i++){
			int x;
			cin>>x;
			ment[x]=true;
			st[x]=BLACK;
		}
		for(int i=1;i<=n;i++){
			if(st[i]!=UNKNOWN && !vis[i]){
				plog<<__LINE__<<" "<<i<<"\n";
				dfs(i);
			}
		}
		for(int i=1;i<=n;i++){
			if(!vis[i] && ment[i]){
				plog<<__LINE__<<" "<<i<<"\n";
				st[i]=BLACK;
				dfs(i);
			}
		}
		if(DEBUG){
			for(int i=1;i<=n;i++) cout<<st[i]<<" ";
		}
		for(int i=1;i<=n;i++){
			if(st[i]==UNKNOWN){
				legal=false;
			}
		}

		for(int u=1;u<=n && legal;u++){
			for(int v:G[u]){
				if(st[u]!=-st[v]){
					legal=false;
					break;
				}
			}
		}
		if(legal) cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值