并查集(hrbust oj 1160 吸血鬼)

并查集我觉得解决有联系的数时,很好用,比如感染,通过接触,感染人,需要计算感染人数,这就是一个很典型的并查集问题。比如下面这个问题,吸血鬼

点击打开链接

可以知道吸血鬼 0 是最原始的根节点,而被其接触的人会变成伪吸血鬼,就是他的子节点,伪吸血鬼接触的人成为伪吸血鬼的子节点,如此往复直到没有接触人为止。

这题要你计算所有吸血鬼的个数只需要查找每个人的根节点,是否为0,也就是真吸血鬼。

而寻找根节点的代码实现如下

int findd(int x) //寻找x的根节点
{
    int r=x;
    while(r!=pre[r]) //per[r]为r的父节点,当r的父节点是他自己时,说明他就是根节点。
        r=pre[r]; // 如果r不是根节点,那么,让r等于它的父节点,一级一级往上寻找,知道找到根节点。
    return r;//返回根节点
}
除了寻找根节点,让两个数有父子关系也是一个重要的操作,代码实现如下

void mix(int x,int y)  //如果x,y不全是吸血鬼,即不在一起,则令x,y有父子关系
{
    int fx=findd(x),fy=findd(y);  //寻找x,y的根节点
    if(fx!=fy)  //判断两者根节点是否相同,即判断是否有关系
    {
        pre[fy]=fx; //如果没有关系,那么令fx成为fy的父亲(谁是谁父亲根本不重要,重要的是联合在一起了)
    }
}
并查集的两组重要操作完成,下面的题目就很容易用代码实现

AC代码如下


#include
#include
#include
#include
#include
#include
using namespace std;
int pre[10005];
int b[10005];
int findd(int x)
{
     int r=x;
    while(r!=pre[r])
        r=pre[r];
        return r;
}
void mix(int x, int y)
{
    int fx = findd(x);
    int fx = findd(y);
    if(fx!=fy)
        pre[fx] = fy;
}
int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))

    {
        if(n==0&&m==0) break;
        for(int i = 0; i < n; i++)
        pre[i] = i;    //开始每个人都是独立的,各自是各自自己的父节点
    while(m--)
    {
        int k,x,y;
        scanf("%d",&k);
        for(int i = 0; i < k; i++)
        {
            scanf("%d",&b[i]);
            if(i > 0)
            {
                int a = findd(b[i]);
                int k = findd(b[i-1]);
                mix(a,k);
            }
        }
    }
    int ans = findd(0),count = 0;
    for(int i = 0; i < n; i++)
        {
            if(findd(i)==ans) count++; // 判断根节点是否为0,即判断是否为吸血鬼
        }
        printf("%d\n",count);
    }


}







你可能感兴趣的:(C)