续并查集学习笔记——Gang团伙题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了续并查集学习笔记——Gang团伙题解相关的知识,希望对你有一定的参考价值。

一言不合先贴题目

Description

在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: 1、 我朋友的朋友是我的朋友; 2、 我敌人的敌人是我的朋友; 所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

Input

第1行为n和m,N小于1000,M小于5000; 以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。

Output

一个整数,表示这n个人最多可能有几个团伙。

Sample Input

6
4
E 1 4
F 3 5
F 4 6
E 1 2

Sample Output

3

HINT

{1},{2,4,6},{3,5}

一开始的想法和ABC野兽那道题一样,可以维护每个点和祖先的关系。而且似乎更简单。于是有了下面的程序

#include<iostream>
#include<cstdio>
using namespace std;
int fa[1010],deep[1010],ans[1010][2],n,m;
int getf(int k){
    if(fa[k]!=k){
        int t=fa[k];
        fa[k]=getf(fa[k]);
        deep[k]=deep[k]+deep[t];
        deep[k]=deep[k]%2;
    }
    return fa[k];
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        fa[i]=i;
        deep[i]=0;
    }
    for(int i=1;i<=m;++i){
        char c[2];
        int x,y;
        scanf("%s%d%d",&c,&x,&y);
        if((c[0]==1)&&(getf(x)!=getf(y))){
            int fx=getf(x);
            int fy=getf(y);
            deep[fx]=(deep[y]-deep[x]+3)%2;
            fa[fx]=fy;
        }
        if((c[0]==0)&&(getf(x)!=getf(y))){
            int fx=getf(x);
            int fy=getf(y);
            deep[fx]=(deep[y]-deep[x]+2)%2;
            fa[fx]=fy;
        }
    }
    
    for(int i=1;i<=n;++i){
        fa[i]=getf(i);
        //cout<<fa[i]<<" "<<deep[i]<<endl;
        ans[fa[i]][deep[i]]++;
    }
    int add=0;
    for(int i=1;i<=n;++i)
    for(int j=0;j<=1;++j)if(ans[i][j]>0){
        add++;
    }
    
    cout<<add;
    return 0;
}

然后、、、、、、就爆0了。

哪里出了问题?忽然发现题设中并没有:我的敌人的朋友是我的敌人。MDZZ!这不符合逻辑啊,虽然NOI从来不讲逻辑。

重新出发,想到分点的方法。通过朋友相关联的,fa[x]=y;通过敌人相关联的,fa[x]=y+n,fa[x+n]=y。该题完美解决。楼下程序:

#include <cstdio>  
#include <cstring>  
#include <iostream>  
#include <algorithm>  
using namespace std;  
int n,m,ans,a[1010];  
int fa[2020];  
int Find(int x)  {  
    if(!fa[x]||fa[x]==x)  
    return fa[x]=x;  
    return fa[x]=Find(fa[x]);  
    }  
void Union(int x,int y)  {  
    x=Find(x);y=Find(y);  
    if(x==y) return ;  
    fa[x]=y;  
    }  
int main(){  
    int i,x,y;  
    char p[10];  
    cin>>n>>m;  
    for(i=1;i<=m;i++)  
    {  
        scanf("%s%d%d",p,&x,&y);  
        if(p[0]==F)  
            Union(x,y);  
        else  
            Union(x,y+n),Union(x+n,y);  
    }  
    for(i=1;i<=n;i++)  
        a[i]=Find(i);  
    sort(a+1,a+n+1);  
    for(i=1;i<=n;i++)  
        if(i==1||a[i]!=a[i-1])  
            ++ans;  
    cout<<ans<<endl;  
    return 0;  
}  

To be continue......

以上是关于续并查集学习笔记——Gang团伙题解的主要内容,如果未能解决你的问题,请参考以下文章

并查集BZOJ1370- [Baltic2003]Gang团伙

BZOJ 1370 [Baltic2003]Gang团伙:并查集虚点

bzoj1370 [Baltic2003]Gang团伙

PAT A1034 Head Of Gang

[并查集]团伙

并查集之团伙(codevs)