题目链接
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增序输出
-
-
思路
- 使用邻接矩阵表示两个人是否是朋友,用邻接表存储一个人的同性朋友
- 给定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/
欢迎讨论和交流!