Vijos1022. Victoria的舞会2

试题请参见: https://vijos.org/p/1022

题目概述

Victoria是一位颇有成就的艺术家, 他因油画作品《我爱北京天安门》闻名于世界. 现在, 他为了报答帮助他的同行们, 准备开一个舞会. 
Victoria准备邀请n个已经确定的人, 可是问题来了:
这n个人每一个人都有一个小花名册, 名册里面写着他所愿意交流的人的名字. 比如说在A的人名单里写了B, 那么表示A愿意与B交流;但是B的名单里不见的有A, 也就是说B不见的想与A交流. 但是如果A愿意与B交流, B愿意与C交流, 那么A一定愿意与C交流. 也就是说交流有传递性. 
Victoria觉得需要将这n个人分为m组, 要求每一组的任何一人都愿意与组内其他人交流. 并求出一种方案以确定m的最小值是多少. 
注意:自己的名单里面不会有自己的名字. 

输入

第一行一个数n. 接下来n行, 每i+1行表示编号为i的人的小花名册名单, 名单以0结束. 1<=n<=200. 

输出

一个数, m.

解题思路

赤裸裸的并查集. 我将每个人想交流的人存在一个 n x n的boolean类型数组(gang)中.

不过有两点需要注意:

1. 如何解决闭包的传递性

2. 解决有向性问题

    对于每一个人(i)检查他想交流的人(j)是否也愿意和他交流(gang[i][j] == true && gang[j][i] == true). 如果不是这样, 需要将gang[i][j]置为false.

遇到的问题

闭包传递性的问题未能以较高效率解决, 因此有2个点超时.
改进之后可以AC.

源代码

#include <iostream>
#include <fstream>

int main() {
    using std::cin;
    // std::ifstream cin;
    // cin.open("input.txt");

    const int SIZE = 200;
    int n = 0;
    bool gang[SIZE][SIZE] = {0};
    int groups[SIZE] = {0};

    // Initialize
    for ( int i = 0; i < SIZE; ++ i ) {
        groups[i] = i;
    }

    // Input
    cin >> n;
    for ( int i = 0; i < n; ++ i ) {
        int person = 0;
        while ( cin >> person ) {
            if ( person != 0 ) {
                gang[i][person - 1] = true;
            } else {
                break;
            }
        }
    }

    // Processing
    for ( int k = 0; k < n; ++ k ) {
        for ( int i = 0; i < n; ++ i ) {
            for ( int j = 0; j < n; ++ j ) {
                if ( gang[i][k] && gang[k][j] ) {
                    gang[i][j] = true;
                }
            }
        }
    }

    for ( int i = 0; i < n; ++ i ) {
        for ( int j = 0; j < n; ++ j ) {
            if ( gang[i][j] && !gang[j][i] ) {
                gang[i][j] = false;
            }
        }
    }

    for ( int i = 0; i < n; ++ i ) {
        for ( int j = i + 1; j < n; ++ j ) {
            if ( gang[i][j] ) {
                groups[j] = groups[i];
            }
        }
    }

    // Output
    int numberOfGroups = 0;
    for ( int i = 0; i < n; ++ i ) {
        if ( groups[i] == i ) {
            ++ numberOfGroups;
        }
    }
    std::cout << numberOfGroups << std::endl;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值