BZOJ 1370 [Baltic2003]Gang團伙:並查集【虛點】

Leohh發表於2017-10-08

題目連結: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 }

 

相關文章