首页 > 代码库 > 【并查集】BZOJ1370- [Baltic2003]Gang团伙

【并查集】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         else57         {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 }

 

【并查集】BZOJ1370- [Baltic2003]Gang团伙