【NOIP2014提高组】寻找道路
https://www.luogu.org/problem/show?pid=2296
满足条件的路径:路径上的所有点的出边所指向的点都与终点连通。
反过来,不满足条件的路径:路径上至少一点的出边所指向的点不与终点连通。
考虑把所有与终点不连通的点以及指向他们的点都删掉,再一遍BFS求出最短路径。
具体做法:
对原图的转置图(将所有边的方向翻转得到的图)从终点开始一遍搜索,把传达不到的爱恋点以及在转置图中它们的所有出点全部标记。注意用两种不同的标记,否则会混乱。
最后在原图跑一遍BFS求出最短路径,有标记的点都不管。
#include <iostream> #include <vector> #include <queue> #define maxn 10005 using namespace std; int n, m, s, t; vector<int> g[maxn], gt[maxn]; bool visited[maxn]; int dist[maxn]; int mark[maxn]; // 0/1表示该点与终点不连通/联通,-1表示该点指向标记0的点 void dfs(int k) { mark[k] = 1; for (int i = 0; i < gt[k].size(); i++) { if (!visited[gt[k][i]]) { visited[gt[k][i]] = true; dfs(gt[k][i]); } } } void bfs() { queue<int> q; q.push(s); while (!q.empty() && dist[t] == 0) { int k = q.front(); q.pop(); if (mark[k] == 1) { for (int i = 0; i < g[k].size(); i++) { if (!dist[g[k][i]]) { dist[g[k][i]] = dist[k] + 1; q.push(g[k][i]); } } } } } int main() { cin >> n >> m; int a, b; for (int i = 1; i <= m; i++) { cin >> a >> b; if (a != b) { g[a].push_back(b); gt[b].push_back(a); } } cin >> s >> t; dfs(t); for (int i = 1; i <= n; i++) { if (mark[i] == 0) { for (int j = 0; j < gt[i].size(); j++) { mark[gt[i][j]] = -1; } } } bfs(); cout << (dist[t] > 0 ? dist[t] : -1) << endl; return 0; }