• 洛谷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
    ", cnt);
        return 0;
    }
    
    
    
  • 相关阅读:
    Jquery 学习一
    响应式设计
    微信开发一
    Ajax 技术二
    Ajax 技术一
    SVN版本控制软件
    正则表达式概述
    编写小游戏:贪吃蛇
    POJ 3356 AGTC(DP-最小编辑距离)
    算法模板の字符串处理
  • 原文地址:https://www.cnblogs.com/handwer/p/11745345.html
Copyright © 2020-2023  润新知