题解:洛谷 P2296 [NOIP 2014 提高组] 寻找道路
洛谷 P2296 [NOIP 2014 提高组] 寻找道路
题意
给定一张边权均为 \(1\) 的 \(n\) 点 \(m\) 边的有向图,给定起点 \(s\) 终点 \(t\)。
要求统计满足下面条件的 \(s\leadsto t\) 路径中的最小长度:
- 路径上每个点出边到达的点都与 \(t\) 连通。
\(n\le10^4\),\(m\le2\times10^5\)。
解法
以 \(t\) 开始跑 BFS,可以预处理出所有无法到达 \(t\) 的点。
再把所有无法到达 \(t\) 的点的前驱也标记为无法到达。
最后跑一遍 BFS 求最短路即可。
时间复杂度
- BFS 预处理,\(O(n+m)\)。
- 标记无法到达,\(O(n+m)\)。
- BFS 最短路,\(O(n+m)\)。
时间复杂度 \(O(n+m)\),可以通过。
代码
/**
* Problem: P2296 [NOIP 2014 提高组] 寻找道路
* Author: OIer_wst
* Date: 2025-07-05
*/
#include <bits/stdc++.h>
using lint = long long;
const int N = 1e4 + 10;
bool vis[N];
int dis[N];
int n, m, s, t;
std::vector<int> g[N], gg[N];
int q[N], hh, tt;
void bfs(int st, const std::vector<int> *g) {
memset(dis, 0x3f, sizeof(dis));
hh = tt = 0, q[0] = st, vis[st] = true, dis[st] = 0;
while (hh <= tt) {
int u = q[hh++];
for (auto v : g[u]) {
if (!vis[v]) {
dis[v] = dis[u] + 1;
vis[v] = true;
q[++tt] = v;
}
}
}
}
int main() {
std::cin >> n >> m;
for (int i = 0, u, v; i < m; ++i) {
std::cin >> u >> v;
g[u].emplace_back(v);
gg[v].emplace_back(u);
}
std::cin >> s >> t;
bfs(t, gg);
hh = 0, tt = -1;
for (int i = 1; i <= n; ++i) {
vis[i] = !vis[i];
if (vis[i]) q[++tt] = i;
}
for (int i = hh; i <= tt; ++i)
for (auto v : gg[q[i]]) vis[v] = true;
if (vis[s]) return std::cout << "-1\n", 0;
bfs(s, g);
std::cout << (dis[t] == 0x3f3f3f3f ? -1 : dis[t]) << "\n";
return 0;
}

浙公网安备 33010602011771号