[BZOJ]1370 Gang团伙 镜像并查集

1370: [Baltic2003]Gang团伙

Time Limit: 2 Sec  
Memory Limit: 64 MB

Submit: 772  
Solved: 424

[
Submit][
Status][
Discuss]

Description

在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

Input

第1行为n和m,N小于1000,M小于5000; 以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。

Output

一个整数,表示这n个人最多可能有几个团伙。

Sample Input

6
4
E 1 4
F 3 5
F 4 6
E 1 2

Sample Output

3

HINT

{1},{2,4,6},{3,5}

Source

[
Submit][
Status][
Discuss] 

HOME Back

很简单的并查集, 因为有敌人或朋友两种种类, 自然而然的想到拆点.

如果a和b是朋友的话, 就把a和b分别的集合合并: 

如果是敌人的话, 那么就把a 和 b + n, a + n 和 b分别的集合合并. 什么意思呢? 因为敌人的敌人是朋友, 所以我们对于某点a, 设一个镜像一般的点a+n, a+n所在的并查集就是a的敌人的并查集, 所以a 和 b + n合并, 满足敌人的敌人是朋友(b+n是b的敌人的集合). a + n 和 b合并同理. 最后处理一遍有多少个集合就可以了.

#include<stdio.h>
const int maxn = 2005;
char ch[1];
bool vis[maxn];
int fa[maxn], ans, n, m;
inline const int read(){
	register int x = 0;
	register char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
	return x;
}
int find(int x) { return (fa[x] == x) ? x : fa[x] = find(fa[x]);}
int main(){
	n = read(), m = read();
	for(int i = 1; i <= 2 * n; ++i) fa[i] = i;
	for(int i = 1; i <= m; ++i){
		scanf("%s", ch);
		int x = read(), y = read();
		if(ch[0] == 'E') fa[find(x)] = find(y + n), fa[find(x + n)] = find(y); 
		else fa[find(x)] = find(y);
	}
	for(int i = 1; i <= n; ++i) vis[find(i)] = true;
	for(int i = 1; i <= 2 * n; ++i) if(vis[i]) ans++;
	printf("%d\n", ans);
}
    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/MaxMercer/article/details/78083743
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞