BZOJ 1370 [Baltic2003]Gang团伙 并查集

题意:
朋友的朋友是我的朋友,敌人的敌人是我的朋友。
n(<=1000)个人给出m(<=5000)对关系表示谁与谁是朋友关系或者是敌对关系。
询问这n个人最多分多少团伙。
解析:
原来做的那个是这个的弱化版…只有朋友关系….
然后这个的话敌对关系我们可以用一种巧妙地拆点法,注意这个方法也是为了秉行上面的那个朋友的朋友…..
朋友关系我们直接合并即可。
敌对关系的话,我们可以考虑把x拆成x与x+n,x+n如果代表与x敌对的话,恰好可以满足我们秉行的那句话,然后最后我们统计一下所有点有多少个不同的团伙即可。
挺有意思的拆点法…
另外,我尝试封装了下并查集,感觉萌萌哒。
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 2010
using namespace std;
class Union_Find_Set
{
    public:
    int fa[N];
    Union_Find_Set(int n)
    {
        for(int i=1;i<=n;i++)
            size[i]=1,fa[i]=i;
    }
    int find(int x)
    {
        if(fa[x]==x)return x;
        return fa[x]=find(fa[x]);
    }
    void Union(int x,int y)
    {
        x=find(x),y=find(y);
        if(x!=y)
        {
            if(size[x]>size[y])swap(x,y);
            fa[x]=y;
            size[y]+=size[x];
        }
    }
    private:int size[N];
}UFS(N-1);
int n,m;
char s[2];
int a[N];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%s%d%d",s,&x,&y);
        if(s[0]=='E')
            UFS.Union(x+n,y),UFS.Union(y+n,x);
        else UFS.Union(x,y);
    }
    for(int i=1;i<=n;i++)a[i]=UFS.find(i);
    sort(a+1,a+n+1);
    int ans=0;
    for(int i=1;i<=n;i++)
        if(a[i]!=a[i-1])ans++;
    printf("%d\n",ans);
}
    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/wzq_QwQ/article/details/48658473
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞