【并查集】BZOJ1370- [Baltic2003]Gang团伙
【题目大意】
在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?
【思路】
水………NOIP的小孩都不屑于玩……
把i拆成i和i+n,其中i表示i的朋友,i+n表示i的敌人。对于(i,j):
(1)i,j是朋友,那么合并i和j。
(2)i,j不是朋友,那么合并i和j+n,j和i+n,代表敌人的敌人是我的朋友。
*注意,如果i和j是敌人,那么它们的敌人不一定是朋友。所有不要合并i+n和j+n。
好水啊……
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=5000; 7 int u[MAXN],h[MAXN],appear[MAXN]; 8 int n,m,gang; 9 10 int find(int x) 11 { 12 int r=x,temp; 13 while (u[r]!=r) r=u[r]; 14 while (x!=r) 15 { 16 temp=u[x]; 17 u[x]=r; 18 x=temp; 19 } 20 return r; 21 } 22 23 void union_set(int fa,int fb) 24 { 25 if (h[fa]>=h[fb]) 26 { 27 u[fb]=fa; 28 if (h[fa]==h[fb]) h[fa]++; 29 } 30 else u[fa]=fb; 31 } 32 33 void init() 34 { 35 for (int i=1;i<=2*n;i++) 36 { 37 u[i]=i; 38 h[i]=1; 39 } 40 } 41 42 void solve() 43 { 44 scanf("%d%d",&n,&m); 45 init(); 46 for (int i=1;i<=m;i++) 47 { 48 char op[2]; 49 int u,v; 50 scanf("%s%d%d",op,&u,&v); 51 if (op[0]=='F') 52 { 53 int fa=find(u),fb=find(v); 54 if (fa!=fb) union_set(fa,fb); 55 } 56 else 57 { 58 int fa=find(u),fb=find(v+n); 59 if (fa!=fb) union_set(fa,fb); 60 fa=find(v),fb=find(u+n); 61 if (fa!=fb) union_set(fa,fb); 62 } 63 } 64 } 65 66 void getans() 67 { 68 for (int i=1;i<=n;i++) u[i]=find(i); 69 memset(appear,-1,sizeof(appear)); 70 gang=0; 71 for (int i=1;i<=n;i++) 72 { 73 if (appear[u[i]]==-1) 74 { 75 gang++; 76 appear[u[i]]=1; 77 } 78 } 79 printf("%d",gang); 80 } 81 82 int main() 83 { 84 solve(); 85 getans(); 86 return 0; 87 }