可以把整个题目描述表示成一个图,每个人都是其中一个结点,两个人如果是朋友则在两个人之间有一条无向边。题目要求的就是给定一个起始结点,一个末尾结点,能不能找到两个结点,使得从起始结点出发经过这两个结点之后到达末尾结点。当然,题目要求比这个稍微复杂,每个节点有男、女两种性别,而且要求经过的两个节点中,第一个节点的性别和起始结点一致,第二个结点的性别和末尾结点一致。
输入第一行给出两个正整数N和M,分别是总人数和友好关系的数量。接下来M行,每行给一对朋友。在此,一个人用4位数字ID表示。为了区分性别,ID前有负号的代表女孩。接下来一行给出一个正整数K,它是查询的数量。接下来K行,每行给出一对起始节点和末尾节点。
对于每个查询,首先在一行中打印他们可以找到的不同对朋友的数量,然后在每行中打印一对朋友的ID。如果恋人A和B的性别相反,则必须首先打印与A性别相同的A的朋友,然后打印与B性别相同的B的朋友。确保每个人只有一个性别。朋友必须按照第一个ID的非降序顺序打印,如果第一个ID相同,则按第二个ID的升序打印。
由于只要求首尾结点之间有两个结点,且结点总数最多才300个,无需DFS或BFS,可以直接采取暴力枚举的方法,在枚举过程中,注意保证第一个节点和首结点性别相同,第二个节点和末尾结点性别相同,此外要避免过早达到头结点或返回首节点的情况出现。具体实现可见代码。
- 有一个大坑,题目按给定的4位数字前有无
-
号作为区别男女的标志,有一个测试点包含了-0000
这样的数据,如果用long long读入,是不会认为它是一个负数的,于是程序自然把其代表的人视作了女性,导致了错误。所以为了保证正确,最好用string读入,以确保前面的-
号不会丢失。 - 输出结点值时要按
%04d
的形式输出,以保证输出数字有4位,不足在高位补0。 - 形成的图为无向图,边为无向边。
- 搜索过程中避免过早达到头结点或返回首节点的情况出现,即保证搜索的两个结点既不等于首节点,也不等于尾结点
#include <bits/stdc++.h>
using namespace std;
using gg = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
unordered_map<gg, bool> boys;
unordered_map<gg, vector<gg>> graph;
gg ni, mi, ki, s, e;
cin >> ni >> mi;
for (gg i = 0; i < mi; ++i) {
string a, b;
cin >> a >> b;
gg ag = abs(stoll(a)), bg = abs(stoll(b));
graph[ag].push_back(bg);
graph[bg].push_back(ag);
boys[ag] = a[0] != '-';
boys[bg] = b[0] != '-';
}
cin >> ki;
while (ki--) {
cin >> s >> e;
s = abs(s), e = abs(e);
vector<array<gg, 2>> ans;
for (gg i : graph[s]) {
if (i != e and i != s and boys[i] == boys[s]) {
for (gg j : graph[i]) {
if (j != e and j != s and boys[j] == boys[e]) {
for (gg k : graph[j]) {
if (k == e) {
ans.push_back({i, j});
}
}
}
}
}
}
cout << ans.size() << "\n";
sort(ans.begin(), ans.end());
for (auto& i : ans) {
cout << setfill('0') << setw(4) << i[0] << " " << setw(4) << i[1]
<< "\n";
}
}
return 0;
}