备战快速复习--day6

并查集

里面主要的函数是Union和findfather两个

Union的注意事项

  • Union只在确定两者原先不需要同一个根,新增加了链接的情况下使用。不然会出现环(一个链条上面的第n个节点连到了头)
  • Union的作用是,发现a和b不一样以后,把a的根节点与b的根节点连在一起。连在一起的是两个的根!(这就会导致,原来一个根是某些点的father,但是现在不是了)
  • 在Union之后会存在一些需要被更新的father,这些点在全部新链接结束以后,通过一轮findfather进行更新就可以。(他们能正确找到自己的组织,但是原来是正确的根,现在不是顶点了,需要更新)
  • 因为在合并的过程中,那时候调用findfather,还是俩根的状态,并不会更新到最优
  • 一定要注意必须大写!U,不然是关键词!

findfather的注意事项

  • 这个在找完以后,要把路途中的点都更新一下子
  • 更新的过程中要注意保留中间数值,因为a被修改直接使用father[a]显然有问题

代码过了样例(应该没问题)

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
int father[1005];
bool pd[1005];
int n,m;
int findfather(int x)
{
    int a=x;
    while(x!=father[x])
        x=father[x];
    int z=a;
    while(a!=father[a])
    {
        z=a;
        a=father[a];
        father[z]=x;
    }
    return x;
}
void Union(int a,int b)
{
    if(findfather(a)!=findfather(b))
        father[findfather(a)]=findfather(b);
}
int main()
{
    scanf("%d %d",&n,&m);
    int temp1,temp2;
    int ans=0;
    memset(pd,0,sizeof(pd));
    for(int i=1;i<=n;i++)
        father[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&temp1,&temp2);
        Union(temp1,temp2);
    }
    /*for(int i=1;i<=n;i++)
        printf("%d ",father[i]);
    printf("
");*/
    for(int i=1;i<=n;i++)
        pd[findfather(i)]=true;
    /*for(int i=1;i<=n;i++)
        printf("%d ",father[i]);
    printf("
");*/
    for(int i=1;i<=n;i++)
        if(pd[i]) ans++;
    printf("%d",ans);
    return 0;
}
View Code

 PAT A1107

这道题是给n个人,然后给出每个人喜欢的类别,类别有1000种(大概),把有喜欢同类的人合并在一起,求总共几个类别

两两合并太麻烦,存一个就行,在全执行结束之后再更新一次father,为了减少运行次数,把所有的father都像hobby的标注对象靠拢,代码如下

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
int father[1005];
int hobby[1005];
int pd[1005];
int ans,n;
bool cmp(int a,int b)
{
    return a>b;
}
int findfather(int x)
{
    int a=x;
    while(x!=father[x])
    {
        x=father[x];
    }
    while(a!=father[a])
    {
        int z=a;
        a=father[a];
        father[a]=x;
    }
    return x;
}
void Union(int a,int b)
{
    if(findfather(a)!=findfather(b))
        father[findfather(a)]=findfather(b);
}
int main()
{
    scanf("%d",&n);
    int num,temp;
    memset(hobby,0,sizeof(hobby));
    memset(pd,0,sizeof(pd));
    for(int i=1;i<=n;i++)
    {
        father[i]=i;
        scanf("%d: ",&num);
        for(int j=1;j<=num;j++)
        {
            scanf("%d",&temp);
            if(hobby[temp]==0)
            {
                hobby[temp]=i;
            }
            else
            {
                Union(i,hobby[temp]);
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        pd[findfather(i)]++;
    }
    sort(pd,pd+1000,cmp);
    while(pd[ans]>0)
    {
        ans++;
    }
    printf("%d
",ans);
    for(int i=0;i<=ans-2;i++)
        printf("%d ",pd[i]);
    printf("%d",pd[ans-1]);
    return 0;
}
View Code
时间才能证明一切,选好了就尽力去做吧!
原文地址:https://www.cnblogs.com/tingxilin/p/12348142.html