原题链接:
题面:
在某个直播间里,观众常常会发送类似这样的弹幕:
鱼越大,鱼刺越大;鱼刺越大,肉越少;肉越少,鱼越小;所以鱼越大,鱼越小
这样通过一连串推导得出一个搞笑的结论的弹幕发送者被称为“相对论大师”。
现在给定一系列已有的推论,请你从给定的推论中挑选一些,组成一条类似于上面的弹幕,成为一名“相对论大师”。
输入格式:
输入第一行是一个正整数 N (1≤N≤1000),表示总共有多少条推论。
接下来的 N 行,每行有两对四个元素,形如下:
A 0 B 1
每对元素表示一个论点:第一个是一个长度不大于 5 的、只包含大小写字母的字符串,称为论点的核心;第二个数字固定为 0 或者 1,代表论点核心的方向属性。为简单理解,你可以将 0 理解为正面方向,1 理解为负面方向。例如:
YuCi 0 Rou 1
就可以理解为
鱼刺大,肉少
。于是一行中的两个论点就形成一条推论,表示第一个核心某个方向的属性能推出第二个核心的某个方向的属性,即
鱼刺越大,肉越少
。输出格式:
按照弹幕格式输出一行,例如:
Yu 0 YuCi 0 YuCi 0 Rou 1 Rou 1 Yu 1 = Yu 0 Yu 1
具体格式要求为:在一行中输出从起始论点到最终论点的所有推论,论点格式与输入相同,论点间以1个空格分隔。随后输出等号(等号前后均有1个空格),最后是相互矛盾的起始和终止论点。
如果有多种方案,选择使用推论最少的;推论条数相同的输出任意一种方案均可。
在方案中每条推论仅可使用一次。保证有解,且给定的推论中没有相同的推论。
输入样例:
5 Yu 0 Yuci 0 Rou 1 Yu 1 Yuci 0 Rou 1 Yuci 0 Gutou 0 Gutou 0 Rou 0
输出样例:
Yu 0 Yuci 0 Yuci 0 Rou 1 Rou 1 Yu 1 = Yu 0 Yu 1
提示:
本题返回结果若为格式错误均可视为答案错误。
解题思路:
BFS搜索,需要对每个论据用map转换为整数x,以方便建图,对于一个论据的相反论据,我们将其编码为x+10000。对于每个点我们都要作为起点跑一次bfs,
代码(CPP):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e4 + 2010;
const int INF = 0x3fffffff;
const int mod = 1000000007;
set<string> core; // 论点核心
map<pair<string, int>, int> mp; // 把论点映射成整数方便建图
map<int, pair<string, int>> mmp; // 逆映射
vector<int> G[maxn];
bool vis[maxn];
int pre[maxn]; // 记录最短路径节点前驱
vector<int> path; // 路径
vector<int> ans; // 答案
int n;
int encode(string s, int x) { // 将每个论据映射为整数,用于建图
int u;
if (core.count(s)) {
if (mp.count({s, x})) {
return mp[{s, x}];
}
u = mp[{s, !x}] + 10000; // 反论点
mp[{s, x}] = u;
mmp[u] = {s, x};
} else {
core.insert(s);
u = mp.size() + 1;
mp[{s, x}] = u;
mmp[u] = {s, x};
}
return u;
}
void dfs(int u) { // 回溯记录bfs的最短路径
if (u == pre[u]) {
path.push_back(u);
return;
}
dfs(pre[u]);
path.push_back(u);
}
void bfs(int start) {
memset(vis, 0, sizeof vis);
path.clear();
queue<int> q;
q.push(start);
vis[start] = true;
pre[start] = start;
while (!q.empty()) {
int u = q.front();
q.pop();
if (abs(u - start) == 10000) { // 判断是否已经找到了逻辑悖论
dfs(u);
if (ans.empty() || path.size() < ans.size()) {
ans = path;
}
return;
}
for (int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!vis[v]) {
vis[v] = true;
pre[v] = u;
q.push(v);
}
}
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
string sa;
int a;
string sb;
int b;
cin >> sa >> a >> sb >> b;
int u = encode(sa, a);
int v = encode(sb, b);
G[u].push_back(v);
}
for (auto ele : mp) {
bfs(ele.second);
}
cout << mmp[ans[0]].first << " " << mmp[ans[0]].second << " ";
cout << mmp[ans[1]].first << " " << mmp[ans[1]].second << " ";
for (int i = 2; i < ans.size(); i++) {
cout << mmp[ans[i - 1]].first << " " << mmp[ans[i - 1]].second << " ";
cout << mmp[ans[i]].first << " " << mmp[ans[i]].second << " ";
}
cout << "= " << mmp[ans[0]].first << " " << mmp[ans[0]].second << " " << mmp[ans[ans.size() - 1]].first << " " << mmp[ans[ans.size() - 1]].second;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << fixed;
cout.precision(18);
solve();
return 0;
}