【图论】问题 C: 黑社会团伙

 

目录

题目描述

输入

输出

样例输入

样例输出

代码 


题目描述

       众所周知,香港的黑社会组织猖獗,警方希望能摸清他们的内部构成情况,特派小生前往调查。经过长期的卧底,小生初步获得了一些资料:整个组织有n个人,任何两个认识的人不是朋友就是敌人,而且满足:①我朋友的朋友是我的朋友;②我敌人的敌人是我的朋友。所有是朋友的人组成一个团伙。现在,警方委派你协助调查,拥有关于这n个人的m条信息(即某两个人是朋友,或某两个人是敌人),请你计算出这个城市最多可能有多少个团伙。

数据范围:2≤N≤2000,1≤M≤5000。

输入

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

输出

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

样例输入

6
4
E 1 4
F 3 5
F 4 6
E 1 2

样例输出

 

3

代码 

#include<bits/stdc++.h> 
using namespace std;
int set1[10001];   // 并查集数组
int rank1[10001];   // 秩数组
int data[10001];
int con[10001];
bool cmp(int a, int b) 
{   
    return a > b; 
}
void Make_Set(int i)   // 初始化集合
{   
    set1[i] = i;  
    rank1[i] = 0;
}
int Find1(int i)   // 查找集合代表元
{   
    if (set1[i] == i)       
        return set1[i];
    return Find1(set1[i]);
}
void Union(int i, int j)   // 合并集合
{   
    i = Find1(i);
    j = Find1(j);
    if (i == j)       
        return;
    if (rank1[i] > rank1[j])   // 按秩合并
        set1[j] = i;
    else  
    {       
        if (rank1[i] == rank1[j])         
            rank1[j]++; 
        set1[i] = j; 
    }
}
int main() 
{   
    int n, m, x, y;
    char a;
    int i, j;
    scanf("%d%d", &n, &m);  // 输入点数和操作数
    for (i = 1; i <= n * 2; i++) 
    {       
        Make_Set(i);  // 初始化n*2个集合
    }  
    for (i = 1; i <= m; i++) 
    {       
        cin >> a;
        scanf("%d%d", &x, &y);
        if (a == 'F')   // 朋友关系合并集合
            Union(x, y);
        if (a == 'E')   // 敌人关系合并集合
        {           
            Union(x, y + n); 
            Union(y, x + n); 
        }
    } 
    int step, ans = 0;
    for (i = 1; i <= n * 2; i++)   // 查找每个点所在集合
        con[i] = Find1(i);
    sort(con, con + n + 1, cmp);  // 降序排序
    for (i = 1; i <= n; i++)  // 统计不同集合个数
    {       
        if (con[i] != con[i - 1])          
            ans++; 
    } 
    printf("%d", ans);  // 输出不同集合总数
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值