[luogu p1892] [BOI2003]团伙

传送门

[BOI2003]团伙

题目描述

给定 \(n\) 个人,他们之间有两个种关系,朋友与敌对。可以肯定的是:

  • 与我的朋友是朋友的人是我的朋友
  • 与我敌对的人有敌对关系的人是我的朋友

现在这 \(n\) 个人进行组团,两个人在一个团队内当且仅当他们是朋友。

求最多的团体数。

输入输出格式

输入格式

第一行一个整数 \(n\) 代表人数。

第二行一个整数 \(m\) 代表每个人之间的关系。

接下来 \(m\) 行每行一个字符 \(opt\) 与两个整数 \(p,q\)

  • 如果 \(opt\)F 代表 \(p\)\(q\) 为朋友。
  • 如果 \(opt\)E 代表 \(p\)\(q\) 为敌人。

输出格式

一行一个整数代表最多的团体数。

输入输出样例

输入样例 #1

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

输出样例 #1

3

说明

对于 \(100\%\) 的数据,\(2 \le n \le 1000\)\(1 \le m \le 5000\)\(1 \le p,q \le n\)

分析

此题是一道很经典的题,与我之前写的一道题非常类似,戳这里看那道题的题解

此题和那道题的方法非常类似,是朋友就合并,是敌人就和敌人的敌人合并。

此题的思路异常简单,所以分析并没有那么多。但是平常思路如此简单的题我是不会写题解的,但是这道题为什么我写了呢?

因为 他是一道非常非常经典的题

不多说废话,直接上代码。

代码

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2020-08-19 01:17:15 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2020-08-19 01:27:21
 */
#include <iostream>
#include <cstdio>

const int maxn = 1005;
int fa[maxn], enemy[maxn];

int find(int x) {
    while (x != fa[x]) x = fa[x] = fa[fa[x]];
    return x;
}

void unite(int x, int y) {
    int fax = find(x);
    int fay = find(y);
    fa[fax] = fay;
    return ;
}

int main() {
    int n, m;
    std :: scanf("%d%d", &n, &m);

    for (int i = 1; i <= n; ++i)
        fa[i] = i;
    
    for (int i = 1; i <= m; ++i) {
        char op;
        int p, q;
        std :: cin >> op >> p >> q;//本来这里想用std :: scanf结果因为字符原因不行,只好用cin了(哭
        if (op == 'F') unite(p, q);//是朋友就合并
        else if (op == 'E') {
            if (!enemy[q]) enemy[q] = p;//记录q的敌人p
            else unite(p, enemy[q]);//将p和q的敌人合并
            if (!enemy[p]) enemy[p] = q;//记录p的敌人q
            else unite(q, enemy[p]);//将q和p的敌人合并
        } else {
            std :: printf("DBXXX AK IOI");//NEVER THIS WAY
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; ++i)
        if (fa[i] == i)
            ++ans;

    std :: printf("%d\n", ans);
    return 0;
}

评测记录

评测记录

posted @ 2020-08-19 14:38  东北小蟹蟹  阅读(92)  评论(1编辑  收藏