P14618 [2019 KAIST RUN Fall] Lexicographically Minimum Walk题解
Spring_rain_Moon · · 题解
很高兴找到一个可以写题解的题!QAQ
核心思路
-
可达性预处理:反向图 BFS 标记所有能到达终点
T 的节点,仅保留这些节点构成的有效子图(无效路径直接排除)。 -
贪心选边:从起点
S 出发,每步选择当前节点出边中「颜色最小」且「终点在有效子图内」的边,保证字典序最优。 -
环与长度检测:若路径中出现重复节点(环),则序列可无限长(输出 TOO LONG);若序列长度超
10^6 ,同样输出 TOO LONG。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
const int MAXL = 1e6;
vector<vector<pair<int, int>>> f_adj(MAXN);
vector<vector<int>> r_adj(MAXN);
vector<bool> rech(MAXN, false);
vector<bool> in_p(MAXN, false);
vector<int> res;
int main(){
int n, m, s, t;
cin >> n >> m >> s >> t;
for (int i = 0; i < m; ++i) {
int u, v, c;
cin >> u >> v >> c;
f_adj[u].emplace_back(v, c);
r_adj[v].push_back(u);
}
queue<int> q;
q.push(t);
rech[t] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : r_adj[u]) {
if (!rech[v]) {
rech[v] = true;
q.push(v);
}
}
}
if (!rech[s]) {
cout << "IMPOSSIBLE" << endl;
return 0;
}
int curr = s;
while (true) {
if (curr == t) {
if (res.size() <= MAXL) {
for (size_t i = 0; i < res.size(); ++i) {
if (i) cout << " ";
cout << res[i];
}
cout << endl;
} else {
cout << "TOO LONG" << endl;
}
return 0;
}
if (in_p[curr]) {
cout << "TOO LONG" << endl;
return 0;
}
in_p[curr] = true;
int min_c = INT_MAX;
int next_n = -1;
for (auto &[v, c] : f_adj[curr]) {
if (rech[v] && c < min_c) {
min_c = c;
next_n = v;
}
}
if (next_n == -1) {
cout << "IMPOSSIBLE" << endl;
return 0;
}
res.push_back(min_c);
if (res.size() > MAXL) {
cout << "TOO LONG" << endl;
return 0;
}
curr = next_n;
}
return 0;
}
The end.