并查集 深入讲解


犯罪团伙(gang.cpp)

题目描述
 警察抓到了n个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从1至n。

输入
 第1行:n(<=500,罪犯数量),m(<50000,关系数量)以下m行:每行两个数:i 和j,中间一个空格隔开,表示罪犯i和罪犯j相互认识。


输出
 第1行:一个整数,犯罪团伙的数量。

样例输入
11 8
1 2
4 3
5 4
1 3
5 6
7 10
5 10
8 9


样例输出
3

#include <iostream>


using namespace std;
int a[1001]={0};

void input(int n)             初始化,每个人是自己的老大;
{
    for(int i=1;i<=n;i++)
        a[i]=i;


}

int  getf(int t)              作用:找t的老大,在顺路中通过递归更改遇到的同伙的老大的老大
{
    if(a[t]==t)
      return t;
    else
      {
          a[t]=getf(a[t]);
          return a[t];
      }                         // 此处的递归: 知道最后的老大,给(前提这个同伙也做了个桥梁参与了找老大过程)还不知道已经换老大的同伙换老大;

}

void merges(int p,int q)     (主要作用换老大)
{
        int t1=getf(q);
        int t2=getf(p);         //找幕后老大;

        if(t1!=t2)              //遵循靠左原则,左边变成右边的老大;
        {
            a[t2]=t1;
        }

}

int main()
{

    int n,m;

    while (cin >>n>>m,n!=0)
{
    input(n);

    int q,p;

    for(int i=0;i<m;i++)
    {
        cin >>q>>p;
        merges(q,p);
    }

    int counts=0;

       for(int i=1;i<=n;i++)
       if(a[i]==i)
       counts++;

    cout << counts-1 << endl;
}




    return 0;

}

第二种类型
Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others.
In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student groups, and makes the following rule in their standard operation procedure (SOP).
Once a member in a group is a suspect, all members in the group are suspects.
However, they find that it is not easy to identify all the suspects when a student is recognized as a suspect. Your job is to write a program which finds all the suspects.
Input
The input file contains several cases. Each test case begins with two integers n and m in a line, where n is the number of students, and m is the number of groups. You may assume that 0 < n <= 30000 and 0 <= m <= 500. Every student is numbered by a unique integer between 0 and n−1, and initially student 0 is recognized as a suspect in all the cases. This line is followed by m member lists of the groups, one line per group. Each line begins with an integer k by itself representing the number of members in the group. Following the number of members, there are k integers representing the students in this group. All the integers in a line are separated by at least one space.
A case with n = 0 and m = 0 indicates the end of the input, and need not be processed.
Output
For each case, output the number of suspects in one line.
Sample Input
100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0
Sample Output
4
1
1



#include <iostream>
using namespace std;


int a[30005]={0};


void input( int n)
{
    for (int i=0;i<n;i++)
        a[i]=i;
}


int getf(int n)
{
    if(a[n]==n)
    return n;


    else
    {
        a[n]=getf(a[n]);
        return a[n];
    }

}

void merges(int v,int u)
{
    int t1=getf(v);
    int t2=getf(u);

    if(t1!=t2)
    a[t2]=t1;


}

int main()
{
    int n,m,k,a,b;

    while (cin >>n>>m,n||m)
    {
         input(n);
       for(int i=0;i<m;i++)
       {
           cin >>k;
           cin >>a;
           for(int i=1;i<k;i++)
           {
               cin>>b;
               merges(a,b);
           }
       }

        int counts=0;


        for(int i=0;i<n;i++)
            if(getf(0)==getf(i))
            counts++;
            cout << counts<< endl;
    }

    return 0;
}

总结 :n个元素在同一组,必然有一个共同的老大,那么就有两个问题
      (1)有几组 ? 
                     for(int i=0;i<n;i++)    
                     if(a[i]==i)  counts++;
      (2)和某元素在一起的有个?  
                     for(int i=0;i<n;i++)   
                     if(getf(a[某元素])==getf[i])  如果有共同的老大,那么必定在同一组
                        counts++;


猜你喜欢

转载自blog.csdn.net/qq_41199502/article/details/80369708
今日推荐