栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

算法刷题【洛谷P2078】朋友

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

算法刷题【洛谷P2078】朋友

题目背景

小明在 A 公司工作,小红在 B 公司工作。

题目描述

这两个公司的员工有一个特点:一个公司的员工都是同性。

A 公司有 N 名员工,其中有 P 对朋友关系。B 公司有 M 名员工,其中有 Q 对朋友关系。朋友的朋友一定还是朋友。

每对朋友关系用两个整数 (Xi,Yi) 组成,表示朋友的编号分别为 Xi,Yi 。男人的编号是正数,女人的编号是负数。小明的编号是 1,小红的编号是 -1。

大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

输入格式

输入的第一行,包含 4 个空格隔开的正整数 N,M,P,Q。

之后 P 行,每行两个正整数 Xi,Yi 。

之后 QQ 行,每行两个负整数 Xi,Yi 。

输出格式

输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。


几乎又是一道并查集模板。

我最开始读题,觉得有一个地方是可以引起歧义的(毕竟不是官方题描述没那么完美很正常):请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣。

两公司?一个公司可以内部消化吗?

后来我发现是自己的问题……

一个公司的员工都是同性。

这样的话没事了。

算法分析:并查集模板,使用 STL map 完成数组的负数下标实现。

代码:

#include 
using namespace std;
map f;
int find(int a) {
    if (f[a] != a)
        return f[a] = find(f[a]);
    else
        return a;
}
int hb(int a, int b) { f[find(b)] = find(a); }

int main() {
    int n, m, p, q;
    cin >> n >> m >> p >> q;
    for (int i = -m; i <= n; i++) {
        if (i == 0) continue;
        f[i] = i;
    }
    f[-1] = f[1];
    int x, y;
    while (p--) {
        cin >> x >> y;
        hb(x, y);
    }
    while (q--) {
        cin >> x >> y;
        hb(x, y);
    }
    int girl = 0, boy = 0;
    for (int i = -m; i < 0; i++) {
        if (find(i) == 1) girl++;
    }
    for (int i = 1; i <= n; i++) {
        if (find(i) == 1) boy++;
    }
    cout << min(boy, girl);
    return 0;
}

最后的统计就是在小明和小红的所有朋友中输出男女总数小的一个。

样例OK,远端……

问题出现了!!!

这个实现按理是没有问题的(至少我现在没有发现,要是以后解决了来说解决方案),题解也有这样的解决方案:

题解 P2078 【朋友】 - SSL_XXY_BlackCloud 的博客 - 洛谷博客

小号测试,题解这个代码的确可以AC

好吧,这样的话那我们换一种思路:map换成数组,男生存储位置不变,女生的位置变成编号的绝对值(因为编号为负 所以也就是相反数)加上n

AC代码:

#include 
using namespace std;

int f[1000001];

int find(int a) {
    if (f[a] != a) {
        return f[a] = find(f[a]);
    } else {
        return a;
    }
}

int hb(int a, int b) { f[find(b)] = find(a); }

int main() {
    int n, m, p, q;
    cin >> n >> m >> p >> q;
    for (int i = 1; i <= n + m; i++) {
        f[i] = i;
    }
    f[n + 1] = f[1];

    int x, y;
    while (p--) {
        cin >> x >> y;
        hb(x, y);
    }
    while (q--) {
        cin >> x >> y;
        hb(-x + n, -y + n);
    }

    int girl = 0, boy = 0;
    for (int i = 1; i <= n; i++) {
        if (find(i) == find(1)) boy++;
    }
    for (int i = n + 1; i <= n + m; i++) {
        if (find(i) == find(1)) girl++;
    }

    cout << min(boy, girl);
    

    return 0;
}


比较这三次的用时,可以看出其实map在时间和空间都没有优势……所以可能只是题解优化稍微好点 然后我的超时/超内存了?

所以以后除非遇到string对其他类型的映射,否则还是老老实实数组吧……

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/317809.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号