BZOJ 1370 [Baltic2003]Gang团伙:并查集【虚点】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1370
题意:
在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:
(1)我朋友的朋友是我的朋友。
(2)我敌人的敌人是我的朋友。
所有是朋友的人组成一个团伙。
告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人。
请你编写一个程序,计算出这个城市最多可能有多少个团伙。
题解:
对于一个人a,建两个点a和a+n。
a+n实际上并不存在,只起到连接的作用,是一个虚点。
所有与a相连的点都是a的朋友。
所有与a+n相连的点都是它的敌人。
如果x和y是朋友,则合并(x,y)。
如果x和y是敌人,则合并(x,y+n)和(y,x+n)。
所有在一个集合内的人,都属于同一个团伙。
统计一下有多少个集合,至少包含一个在[1,n]内的点,即为答案。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 2005 5 6 using namespace std; 7 8 int n,m; 9 int ans=0; 10 int par[MAX_N]; 11 bool vis[MAX_N]; 12 13 void init_union_find() 14 { 15 for(int i=1;i<=n*2;i++) 16 { 17 par[i]=i; 18 } 19 } 20 21 int find(int x) 22 { 23 return par[x]==x?x:par[x]=find(par[x]); 24 } 25 26 void unite(int x,int y) 27 { 28 int px=find(x); 29 int py=find(y); 30 if(px==py) return; 31 par[px]=py; 32 } 33 34 bool same(int x,int y) 35 { 36 return find(x)==find(y); 37 } 38 39 void read() 40 { 41 cin>>n>>m; 42 init_union_find(); 43 int x,y; 44 char p; 45 for(int i=0;i<m;i++) 46 { 47 cin>>p>>x>>y; 48 if(p=='F') unite(x,y); 49 else 50 { 51 unite(x+n,y); 52 unite(y+n,x); 53 } 54 } 55 } 56 57 void solve() 58 { 59 memset(vis,false,sizeof(vis)); 60 for(int i=1;i<=n;i++) 61 { 62 int p=find(i); 63 if(!vis[p]) 64 { 65 vis[p]=true; 66 ans++; 67 } 68 } 69 } 70 71 void print() 72 { 73 cout<<ans<<endl; 74 } 75 76 int main() 77 { 78 read(); 79 solve(); 80 print(); 81 }