题目描述

在某城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足:

1、我朋友的朋友是我的朋友;

2、我敌人的敌人是我的朋友;

所有是朋友的人组成一个团伙。告诉你关于这n个人的m条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能有多少个团伙?

输入

第1行为n和m,1<n<1000,1≤m≤100 000;

以下m行,每行为p x y,p的值为0或1,p为0时,表示x和y是朋友,p为1时,表示x和y是敌人。

输出

一个整数,表示这n个人最多可能有几个团伙。

 

样例输入

6 4

1 1 4

0 3 5

0 4 6

1 1 2

样例输出

3

思路

这是并查集的一种运用,首先我们先将所有父节点初始化为他们自己;

如果输入的两人是朋友,则进入并集函数,如果两人是敌人,则分别与对方的敌人并集,并记录各自的敌人数量;

最后遍历所有人,只要他的父节点是他自己便是根节点,而我们只需找到所有的根节点即为所有的团体数

代码:

#include<bits/stdc++.h>

using namespace std;

int tuan[100001],di[1001][1001];//tuan用来记录团伙,di[i][j]用来存储i的第j个敌人

int find(int x)//查集函数

{

       if(tuan[x]!=x)

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

       return tuan[x];

}

void unionn(int r1,int r2)

{

       tuan[r2]=r1;//团伙的并集

}

int main()

{

       int n,m;

       cin>>n>>m;

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

       tuan[i]=i;//先将所有父节点定为他们自己

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

       {

              int p,x,y;

              cin>>p>>x>>y;

              if(p==0)//p==0时他们是朋友,所以并集

              {

                     if(find(x)!=find(y))

                     unionn(find(x),find(y));

              }

              Else//p==1时他们是敌人,将敌人的敌人并集

              {

                     for(int j=1;j<=di[x][0];j++)

                     {

                            if(find(y)!=find(di[x][j]))

                            unionn(find(y),find(di[x][j]));

                     }     

                     for(int j=1;j<=di[y][0];j++)

                     {

                            if(find(x)!=find(di[y][j]))

                            unionn(find(x),find(di[y][j]));

                     }

                     di[y][0]++;//记录敌人的个数

                     di[y][di[y][0]]=x;

                     di[x][0]++;

                     di[x][di[x][0]]=y;

                    

              }

        }

        int a=0;//要找到集合的个数,只需找到根节点的个数,a用来记录根节点的个数

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

       if(tuan[i]==i) //当父节点就是自己本身时,就是那个集合的根节点

       a++;

       cout<<a<<endl;

}