PAT甲级1139First Contact

题目链接

https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312

题解

题目要求

  • 背景

    男生A喜欢女孩B,A找男生C让女孩D跟B说,其中C是A的朋友,D是B和C的朋友。女生也是这样联系男生

  • 输入

    • N:人的数量,1到300
    • M:朋友关系的数量
    • M个朋友关系:用4位数字表示一个人,其中负数代表性别是女生
    • K:查询数量,不超过100
    • K次查询:每次查询是A和B的ID,假设A喜欢B
  • 输出

    • 输出有几对C和D可以帮助A联系B

    • 输出这几对C和D

      • 如果A和B是异性,则A和C应该是同性,B和D同性;如果A和B是同性,则这4人性别应该相同

        即A和C同性,B和D同性

      • 先按C的ID非降序输出,再按D的ID增序输出

思路

  1. 使用邻接矩阵表示两个人是否是朋友,用邻接表存储一个人的同性朋友
  2. 给定A和B以后,枚举A的朋友C,枚举B的朋友D,如果C和D是朋友则保存C和D

注意点

  • 输出时要以4位数字输出,用printf("%04d"),第二和第三个测试点都测试了这个
  • 如果用int接收一对朋友,-0000和0000对于int来说都是0,将无法得知这个人的性别
    • 在这里我对他们的id进行了处理:把女生映射到[0,9999],男生映射到[10000,19999]
    • 也可以使用其他的哈希方法
  • 正常回路为A-C-D-B,不可以形成A-B-D-B或A-C-A-B的回路,即AD不相等、BC不相等
  • 写循环代码时注意一些变量是否会随着循环运行而改变,比如数组大小、外层循环变量是否被内层循环改变

代码

// Problem: PAT Advanced 1139
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312
// Tags: Graph Hash

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

bool isFriend[20000][20000]; // 邻接矩阵
vector<int> friends[20000]; // 邻接表,同性朋友

struct Helper{
    int c, d;
};

int transform(string s){
    // 将负数映射到[0,9999],将正数映射到[10000,19999]
    if (s[0] == '-')
        return abs(stoi(s));
    else
        return 10000 + stoi(s);
}

int restore(int num){
    // 将transform得到的[0,19999]的数字映射到[0,9999],即原来的[-9999,9999]取绝对值得到[0,9999],以进行输出
    if (num > 9999)
        return num - 10000;
    else
        return num;
}

bool helperCmp(Helper& h1, Helper& h2){
    return h1.c == h2.c ? h1.d < h2.d : h1.c < h2.c;
}

int main()
{
    int n, m, k, a, b, c ,d;
    string s, t;
    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; i++){ // 将图存入邻接矩阵和邻接表
        cin >> s >> t;
        a = transform(s);
        b = transform(t);
        isFriend[a][b] = isFriend[b][a] = true;
        if ( (a<10000 && b<10000) || (a>9999 && b>9999) ){ // 同性则存储到邻接表
            friends[a].push_back(b);
            friends[b].push_back(a);
        }
    }

    scanf("%d", &k);
    while (k--){
        cin >> s >> t;
        a = transform(s);
        b = transform(t);
        vector<Helper> helpers;
        for (auto it1 = friends[a].begin(); it1 != friends[a].end(); it1++){
            c = *it1;
            if (c == b) // C和B不能是一个人
                continue;
            for (auto it2 = friends[b].begin(); it2 != friends[b].end(); it2++){
                d = *it2;
                if (d == a) // D和A不能是一个人
                    continue;
                if (isFriend[c][d])
                    helpers.push_back({restore(c), restore(d)});
            }
        }
        sort(helpers.begin(), helpers.end(), helperCmp);
        printf("%d
", helpers.size());
        for (auto it = helpers.begin(); it != helpers.end(); it++)
            printf("%04d %04d
", it->c, it->d);
    }

    return 0;
}

一份超时的代码

// Problem: PAT Advanced 1139
// URL: https://pintia.cn/problem-sets/994805342720868352/problems/994805344776077312
// Tags: Graph Hash Map

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;

struct Helper{
    string c, d;
};

bool helperCmp(Helper& h1, Helper& h2){
    return abs(stoi(h1.c)) == abs(stoi(h2.c)) ? abs(stoi(h1.d)) < abs(stoi(h2.d)) : abs(stoi(h1.c)) < abs(stoi(h2.c));
}

int main()
{
    int n, m, k;
    string a, b, c, d;
    unordered_map<string, vector<string>> friends; // 会很耗时
    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; i++){ // 存储朋友关系
        cin >> a >> b;
        if (a[0] != '-')
            a = '+' + a;
        if (b[0] != '-')
            b = '+' + b;
        friends[a].push_back(b);
        friends[b].push_back(a);
    }
    
    scanf("%d", &k);
    while (k--){
        cin >> a >> b; // a喜欢b
        if (a[0] != '-')
            a = '+' + a;
        if (b[0] != '-')
            b = '+' + b;
        vector<Helper> helpers;
        // 下边这个大的for循环也很耗时间
        for (auto it1 = friends[a].begin(); it1 != friends[a].end(); it1++){
            c = *it1; // a的朋友c
            if (b == c || a[0] != c[0]) // a和c不可以是同一个人,且应该是同性
                continue;
            for (auto it2 = friends[c].begin(); it2 != friends[c].end(); it2++){
                d = *it2; // c的朋友d
                if (a == d || b[0] != d[0]) // a和d不可以是同一个人,且应该是同性
                    continue;
                if (find(friends[d].begin(), friends[d].end(), b) != friends[d].end()){
                    helpers.push_back({c, d});
                }
            }
        }
        sort(helpers.begin(), helpers.end(), helperCmp); // 按id升序存储,达到题目输出要求
        int num = helpers.size();
        printf("%d
", num);
        for (int i = 0; i < num; i++)
            printf("%04d %04d
", abs(stoi(helpers[i].c)), abs(stoi(helpers[i].d)));
    }
    return 0;
}

参考链接

https://blog.csdn.net/liuchuo/article/details/79065004


作者:@臭咸鱼

转载请注明出处:https://www.cnblogs.com/chouxianyu/

欢迎讨论和交流!


原文地址:https://www.cnblogs.com/chouxianyu/p/13597324.html