并查集“好朋友” && PAT1107 Social Clusters (30 分)

典型用途:求解等价类问题

实现关键:

1. int father[N];    //father[i]表示元素i所在类的代表元。

如果father[i]=i,说明i是这棵树的根结点(也即这个等价类的代表元),可利用该特点递推地找代表元。

若两个元素的根结点相同,说明在同一个等价类中。仅当还不在一个等价类中时才需要合并,注意:合并是让一个等价类的根结点成为另一个等价类的根结点的父亲,如father[fa] = fb,绝对不是直接让一个结点成为另一个结点的父亲。

2.int isRoot[N];      //合并操作都完成之后,一遍遍历统计等价类的个数以及各类中元素个数。

初始化为全0,合并完成后遍历时isRoot[findfather[i]]++。

 

好朋友

1. 初始化函数Init()里注意是用预定义的MAX还是用需要读取之后值才有效N。如果用N的话,就必须读入N值以后再初始化。用MAX是把整个数组都初始化了,用读入后的N只初始化了前面一部分。一定要具体分析,如果是读入的数据作数组下标的话,尤其要小心,整个数组都会用到所以要用MAX。

2. count = N;//不能放在全局,因为那时候N值未读入,count = N即count也为0。既然本意是想让count等于读入后的N值,那就读入以后在main里赋值。

3.不能直接把一个的父结点设成另一个,必须通过Union函数来合并等价类。犯过的错就要记住。

//统计等价类的数目以及每个等价类的元素个数
#include 
using namespace std;
#define MAX 110

int N, M;
int father[MAX];
int isRoot[MAX];

void Init(int n){
    for (int i=1; i<=n; i++) {
        father[i] = i;
        isRoot[i] = 0;
    }
}

int findFather(int x){
    while (x != father[x]) {
        x = father[x];
    }
    return x;
}

void Union(int a, int b){
    int fathera = findFather(a);
    int fatherb = findFather(b);
    if (fathera != fatherb) {
        father[fathera] = fatherb;
    }
}

int main(int argc, const char * argv[]) {
    scanf("%d %d", &N, &M);
    Init(N);

    int a, b;
    for (int i=0; i

1107

更巧妙的解法:开数组int course[N],元素course[h]表示爱好为h的任意一个人的下标。类似打表,且打表和查表在读取输入时一并完成了。初始化为全0,当读到第i个人有个爱好j时,若course[j]=0说明i是第一个有j爱好的人,改course[j]为i;若course[j]不为0,说明此前已经有人有这个爱好了且其下标是course[j],所以i与course[j]应当属于一个圈子,于是调用Union(i, findfather(course[j]))。或者就调用Union(i, course[j])应该也可以。

#include 
#include 
#include 
#define MAXN 1010
using namespace std;

bool cmp(int a, int b){
    return a > b;
}

struct people{
    vector hobby;
}People[MAXN];

int father[MAXN];
int isRoot[MAXN];

void Init(int n){
    for (int i=1; i<=n; i++) {
        father[i] = i;
        isRoot[i] = 0;
    }
}

int findFather(int x){
    while (x != father[x]) {
        x = father[x];
    }
    return x;
}

bool Intersect(vector h1, vector h2){
    bool result = false;
    bool hobbies[MAXN] = {false};
    for (vector::iterator it=h1.begin(); it!=h1.end(); it++) {
        hobbies[*it] = true;
    }
    for (vector::iterator it=h2.begin(); it!=h2.end(); it++) {
        if (hobbies[*it]) {
            result = true;
            break;
        }
    }
    return result;
}

void Union(int a, int b){
    int fa = findFather(a);
    int fb = findFather(b);
    if (fa != fb && Intersect(People[a].hobby, People[b].hobby)) {
        father[fa] = fb;
    }
}

int main(int argc, const char * argv[]) {
    int N, K, h;
    scanf("%d", &N);
    Init(N);
    for (int i=1; i<=N; i++) {
        scanf("%d: ", &K);
        for (int j=0; j

 

 

你可能感兴趣的:(PAT,PAT,1107,Social,Clusters,并查集,好朋友)