算法刷题【洛谷P2078】朋友

异想之旅:本人原创博客完全手敲,绝对非搬运,全网不可能有重复;本人无团队,仅为技术爱好者进行分享,所有内容不牵扯广告。本人所有文章仅在CSDN、掘金和个人博客(一定是异想之旅域名)发布,除此之外全部是盗文!


题目背景

小明在 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 <bits/stdc++.h>
using namespace std;
map<int, int> 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 <bits/stdc++.h>
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对其他类型的映射,否则还是老老实实数组吧……

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

异想之旅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值