并查集-朋友问题

例一:

整个组织有n个人,任何两个认识的人不是朋友就是敌人,而且满足:①我朋友的朋友是我的朋友;②我敌人的敌人是我的朋友。所有是朋友的人组成一个团伙。现在,警方委派你协助调查,拥有关于这n个人的m条信息(即某两个人是朋友,或某两个人是敌人),请你计算出这个城市最多可能有多少个团伙。

数据范围:2N10001M1000

输入数据:第一行包含一个整数N,第二行包含一个整数M,接下来M行描述M条信息,内容为以下两者之一:“F x y”表示xy是朋友;“E x y”表示xy是敌人(1xyN)。

输出数据:包含一个整数,即可能的最大团伙数。

样例:

输入:6               

      4

      E 1 4

      F 35

      F 4 6

      E 1 2

输出:3

#include<iostream>
using namespace std;
int root[1001]={0};
int relate[1001][1001]={0};
int father(int n){
if (root[n]==-1)
   {
   return n;
   }
else return father(root[n]);
}

int hb(int x,int y){
int n,m;
n=father(x);
m=father(y);
if (n<m){
   root[m]=n;
   }
else {
   root[n]=m;
   }
return 0;
}
int mains(){
int n,m;
int i,j,k;
char c;
int x,y;
cin>>n>>m;
for (i=1;i<=1001;i++)
   {
   root[i]=-1;
   }
for (i=1;i<=m;i++)
   {
   cin>>c>>x>>y;
   if (c==’E’)
    {
    relate[y][x]=1;//记录相互的关系
    relate[x][y]=1;
    }
   if (c==’F’)
    {
    hb(x,y);
    }
}
for (i=1;i<=n;i++){//遍历关系,合并我的敌人的敌人即朋友
   for (j=1;j<i;j++)//通过以当前位置的前一位置向下辐射,即每次查找一个方阵
    {
    if(relate[i][j]){
     for (k=1;k<i;k++)//小于i是为了防止二次合并,即构成方阵
      {
      if (relate[j][k])
       {
       hb(k,i);
       }
      }
     }
   }
   cout<<endl;
}
int s=0;
for (i=1;i<=n;i++)
   {
   if (root[i]==-1)s++;
   }
cout<<s;

return 0;
}/*首先,如果两人是朋友,那么就把两人合并。

    除此之外,我们再维护一个e[i],表示i的一个敌人。如果两人是敌人,那么如果e[i]为空,就更新e[i],否则,就把e[i]和j合并。根据敌人的敌人是朋友的原则,如果j和i是敌人,那么j同e[i]则是朋友,所以合并。同样的,对于i和e[j],也是如此。最后统计一下根结点就行了。

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<iostream>

using namespace std;

int n,m;

const int maxn=1000;

int f[maxn+10],e[maxn+10];

int find(int x)

{

    if (f[x]==x) return f[x];

    f[x]=find(f[x]);

    return f[x];

}

void together(int a,int b)

{

     int aa=find(a),bb=find(b);

     f[aa]=f[bb];

 }

int main()

{

    scanf(“%d%d”,&n,&m);

    for (int i=1; i<=n; i++)

        f[i]=i;

    while (m–)

    {

        char flag=(getchar(),getchar());

        int a,b;

        scanf(“%d%d”,&a,&b);

        if (flag==’F’) together(a,b);

        else

        {

            if (!e[a]) e[a]=b;

            else  together(e[a],b);

            if (!e[b]) e[b]=a;

            else  together(e[b],a);

        }

          }

    int ans=0;

    for (int i=1; i<=n; i++)

        if (f[i]==i) ans++;

    printf(“%d\n”,ans);

return 0;

}

*/

 

例二:

 

More isbetter

Time Limit: 5000/1000 MS (Java/Others) Memory Limit:327680/102400 K (Java/Others)
Total Submission(s): 7622 Accepted Submission(s): 2797

Problem Description

Mr Wang wants some boys tohelp him with a project. Because the project is rather complex, the moreboys come, the better it will be. Of course there are certain requirements.

Mr Wang selected a room big enough to hold the boys. The boy who are not beenchosen has to leave the room immediately. There are 10000000 boys in the roomnumbered from 1 to 10000000 at the very beginning. After Mr Wang’s selectionany two of them who are still in this room should be friends (direct orindirect), or there is only one boy left. Given all the direct friend-pairs,you should decide the best way.

 

Input

The first line of the inputcontains an integer n (0 ≤ n ≤ 100 000) – the number of direct friend-pairs.The following n lines each contains a pair of numbers A and B separated by asingle space that suggests A and B are direct friends. (A ≠ B, 1 ≤ A, B ≤10000000)

 

Output

The output in one linecontains exactly one integer equals to the maximum number of boys Mr Wang maykeep.

 

Sample Input

4

1 2

3 4

5 6

1 6

4

1 2

3 4

5 6

7 8

 

Sample Output

4

2

 

Hint

 

A and B are friends(direct or indirect), B and C are friends(direct orindirect),

then A and C are also friends(indirect).

 

 In the first sample {1,2,5,6} isthe result.

In the second sample {1,2},{3,4},{5,6},{7,8} are four kinds of answers.

 

#include<stdio.h>

#include<string.h>

intf[10000001];

boolroot[10000001];

intsum=0;

intfind(int a);

voidUnino(int a,intb);

intmain(void){

   int n,a,b;

 

   while(scanf(“%d”,&n)!=EOF){

   for(intj=0;j<10000001;j++){

      root[j]=true;

      f[j]=1;

   }

   for(inti=0;i<n;i++){

       scanf(“%d%d”,&a,&b);

      a=find(a);

      b=find(b);

      if(a!=b){

         Unino(a,b);

      }

   }

   

   for(intk=0;k<10000001;k++){

       if(f[k]>sum&&root[k])

        sum=f[k];

   }

   printf(“%d\n”,sum);

   sum=0;

   }

   return 0;

}

intfind(int a){

   while(!root[a])a=f[a];

   return a;

}

voidUnino(int a,intb){

   if(f[a]>f[b]){

      f[a]=f[a]+f[b];

      f[b]=a;

      root[b]=false;

   }

   else{

      f[b]=f[a]+f[b];

      f[a]=b;

      root[a]=false;

   }

}

 

    原文作者:犯罪团伙问题
    原文地址: https://blog.csdn.net/wccmfc123/article/details/8280339
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞