洛谷P1892《[BOI2003]团伙》

原创建时间:2018-07-28 20:17:29

本题来自「2018 SDSC」Day 3 考试题目

题目链接

题目描述

1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是:

我朋友的朋友是我的朋友;

我敌人的敌人也是我的朋友。

两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。

Input/Output 格式 & 样例

输入格式

输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。

第二行M(1<=M<=5000),表示关于强盗的信息条数。

以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。

输入数据保证不会产生信息的矛盾。

输出格式

输出文件gangs.out只有一行,表示最大可能的团伙数。

输入样例

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

输出样例

3

解题思路

很显然这是一道并查集的题目

初始时我们把每一个人单独列为一个团伙

由题可得,这道题主要有如下合并方式:

  1. 我的朋友是我的朋友
  2. 我的朋友的朋友是我的朋友
  3. 我的敌人的朋友是我的敌人
  4. 我的敌人的敌人是我的朋友

那么我们要另开一个\(Enemy[\ ]\)数组,\(Enemy[i]\)表示 \(i\)其中一个敌人

每次合并敌人的时候,先判断是否有记录过敌人:

  • 如果有,那么就把当前的敌人和记录的敌人合并在一个团伙里
  • 如果没有,那么就把当前的敌人记录

最后开一个数组\(count[\ ]\)进行统计

这里要注意几个点:

  1. 开始时并查集数组要开两倍,因为你要把敌人和朋友存在一个数组里
  2. 合并敌人时要注意合并的不是敌人本身,而是\(Find(\)敌人\()\)
  3. 最后统计的时候也要统计\(Find(\)敌人\()\)

对了,注意输入...

建议使用iostream...

别问我为什么会写上这句话

53vhll.png

代码实现

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;

const int MAXN = 1000 + 10;

int U[MAXN * 2], Enemy[MAXN * 2], n, m;
int count[MAXN * 2], cnt;

inline int getint() {
    int s = 0, x = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') x = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        s = s * 10 + ch - '0';
        ch = getchar();
    }
    return s * x;
}

inline void putint(int x) {
    if (x < 0) {
        x = -x;
    }
    if (x >= 10) {
        putint(x / 10);
    }
    putchar(x % 10 + '0');
}

int Find(int x) {
    if (U[x] == x) return x;
    return U[x] = Find(U[x]);
}

void Union(int x, int y) {
    x = Find(x), y = Find(y);
    if (x == y) return;
    U[x] = y;
    return;
}

int main(int argc, char *const argv[]) {
    freopen("P1892.in", "r", stdin);
    cin >> n >> m;
    for (int i = 0; i <= n * 2; ++i) U[i] = i;
    for (int i = 1; i <= m; ++i) {
        char c;
        int x, y;
        cin >> c >> x >> y;
        switch(c) {
            case 'F': {
                Union(x, y);
                break;
            }
            case 'E': {
                if (Enemy[x] == 0) Enemy[x] = Find(y);
                else Union(y, Enemy[x]);
                if (Enemy[y] == 0) Enemy[y] = Find(x);
                else Union(x, Enemy[y]);
            }
        }
    }
    for (int i = 1; i <= n; ++i) ++count[Find(i)];
    for (int i = 1; i <= n; ++i) if (count[i]) ++cnt;
    printf("%d\n", cnt);
    return 0;
}


posted @ 2019-10-26 20:16  Handwer  阅读(179)  评论(0编辑  收藏  举报