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不相等
  • 写循环代码时注意一些变量是否会随着循环运行而改变,比如数组大小、外层循环变量是否被内层循环改变

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// 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\n", helpers.size());
for (auto it = helpers.begin(); it != helpers.end(); it++)
printf("%04d %04d\n", it->c, it->d);
}

return 0;
}

一份超时的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 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\n", num);
for (int i = 0; i < num; i++)
printf("%04d %04d\n", 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/

欢迎讨论和交流!