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 }

 

posted @ 2017-10-08 10:56  Leohh  阅读(322)  评论(0编辑  收藏  举报