1. 程式人生 > >5971 Wrestling Match (種類並查集)

5971 Wrestling Match (種類並查集)

Wrestling Match

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 3367    Accepted Submission(s): 1210 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

先吐槽一下這個題的資料

8 3 1 1

1 2

3 4

5 6

7 8

這組資料應該輸出的是NO吧,雖然前6個點能形成二分圖,但是形成了3個二分圖啊,我們並不能把他們分成兩組啊

網上的其它題解幾乎全輸出的YES,我有點懷疑我題意理解錯了,如果我理解錯了,請給我指出

我用的種類並查集寫的,兩個節點的關係為1代表屬於同一組,兩個節點關係為0代表不屬於同一組,m場比賽每場比賽的兩個節點都不屬於同一組,join的同時判斷是否和之前的關係矛盾,最後給出a個好人,b個壞人,每個好人與b個壞人join一下,a個好人互相join一下,b個壞人互相join一下,同時判斷矛盾,標記以上所有出現的點,最後判斷如果存在沒有被標記的,就直接輸出NO,最後還要判斷一下這個種類並查集中有多少個連通塊,特殊情況如果某一個連通塊存在一個已經明確好人壞人的點,就不計數,連通塊大於1輸出NO

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int pre[MAXN],re[MAXN];
int G[MAXN],B[MAXN];
int vis[MAXN];
int vis1[MAXN];
int Find(int x)
{
	if(x == pre[x]) {
		return x;
	}
	else {
		int t = pre[x];
		pre[x] = Find( pre[x] );
		int rf = re[x];
		int rff = re[t];
		re[x] = (rf == rff);
		return pre[x];
	}
}
bool join(int x,int y,int r)
{
	int fx = Find(x);
	int fy = Find(y);
	if(fx != fy) {
		pre[fy] = fx;
		re[fy]  =  ( re[y] + re[x] ) % 2;
	}
	else {
		if( re[x] == re[y] ) {
			return false;
		}
	}
	return true;
}
int main(void)
{
	int n,m,a,b;
	int u,v;
	while(scanf("%d %d %d %d",&n,&m,&a,&b) != EOF) {
		for(int i = 1; i <= n; i++) {
			pre[i] = i;
			re[i] = 1;
			vis[i] = 0;
			vis1[i] = 0;
		}
		int flag = 0;
		while(m--) {
			scanf("%d %d",&u,&v);
			vis[u] = 1;
			vis[v] = 1;
			if( !flag ) if( !join(u,v,0) ) flag = 1;
		}
		for(int i = 1; i <= a; i++) {
			scanf("%d",&G[i]);
			vis[G[i]] = 1;
		}
		for(int i = 1; i <= b; i++) {
			scanf("%d",&B[i]);
			vis[B[i]] = 1;
		}
		if(!flag) {
			if(a) {
				int uu = G[1];
				for(int i = 2; i <= a; i++) {
					if( !flag ) if( !join(uu,G[i],1)) flag = 1;
				}
			}
			if(b) {
				int uu = G[1];
				for(int i = 2; i <= b; i++) {
					if( !flag ) if( !join(uu,B[i],1)) flag = 1;
				}
			}
			for(int i = 1; i <= a; i++) {
				for(int j = 1; j <= b; j++) {
					if( !flag ) if( !join(G[i],G[j],0) ) flag = 1;
				}
			}

		}
		for(int i = 1;i <= n; i++) {
			if(!vis[i]) {
				flag = 1;
			}
		}
		for(int i = 1; i <= a; i++) {
			vis1[Find(G[i])] = 1;
		}
		for(int i = 1; i <= b; i++) {
			vis1[Find(B[i])] = 1;
		}
		int cnt = 0;
		for(int i = 1; i <= n; i++) {
			int t = Find(i);
			if(i == t && !vis1[t]) {
				cnt++;
			}
		}
		if(cnt > 1) flag = 1;
		if(flag) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}