条件第一步,要能到达 \(t\) 点,建反图跑一遍。记录哪些点可行。
第二步,扫描每个点,若其旁边均为标记过的,说明点的出边所指向的点都直接或间接与终点连通。记录这个点第二次
第三步,在原边枚举每条边,若两个节点均被记录了第二次,加入一个新图,否则扔掉。
对新图进行 BFS 即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n, m, s, t, vis[10005], can[10005], dis[10005];
vector<int> g[10005], f[10005], h[10005];
void dfs(int u){
vis[u] = 1;
for(int i = 0; i < g[u].size(); i ++){
if(!vis[g[u][i]]){
dfs(g[u][i]);
}
}
}
queue<int> q;
int main(){
cin >> n >> m;
for(int i = 1; i <= m; i ++){
int u, v; cin >> u >> v;
f[u].push_back(v); g[v].push_back(u);
}
cin >> s >> t;
dfs(t);
for(int i = 1; i <= n; i ++){
can[i] = 1;
for(int j = 0; j < f[i].size(); j ++){
can[i] = min(can[i], vis[f[i][j]]);
}
}
for(int i = 1; i <= n; i ++){
for(int j = 0; j < g[i].size(); j ++){
if(can[i] && can[g[i][j]]) h[g[i][j]].push_back(i);
}
}
for(int i = 1; i <= n; i ++) dis[i] = -1;
q.push(s); dis[s] = 0;
while(q.size()){
int now = q.front(); q.pop();
for(int i = 0; i < h[now].size(); i ++){
if(dis[h[now][i]] == -1){
dis[h[now][i]] = dis[now] + 1;
q.push(h[now][i]);
}
}
}
cout << dis[t];
return 0;
}
标签:10005,NOIP2014,int,题解,back,dfs,vis,P2296
From: https://www.cnblogs.com/zhangzirui66/p/18665592