寻找道路
题目描述
1.预处理反向建边。
2.从终点开始bfs,标记从终点开始可以走到的点。
3.枚举每一个点,如果这个点没有被标记,则枚举它的每一条出边(反向后的),如果它指向的点被标记,则说明这个被标记的点不合法,删除。
4.在合法点上进行bfs。
bfs有个性质是在第一次到达终点时的距离最短。
参考的题解:
牛客题解
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define INF 0x3f3f3f3f
#define PII pair<int, int>
#define rep(i, l, r) for (int i = l; i < r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define rep2(i, l, r) for (int i = l; i * i <= r; i++)
#define rep3(i, l, r) for (LL i = l; i * i * i <= r; i++)
#define Min(a, b) a > b ? b : a
#define Max(a, b) a > b ? a : b
#define endl '\n'
#define debug "-----"
using namespace std;
typedef long long LL;
const LL mod = 1e9;
const int N = 1e6+10 ,M = 20100;
LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; }
int n,m;
int s,e;
vector<int>mp[M];
bool st_can[N];
bool st[N];
int dist[N];
void bfs_end(){
st_can[e] = 1;
queue<int>q;
q.push( e );
while( q.size() ){
int t = q.front();
q.pop();
rep( i , 0 , mp[t].size() )
if( !st_can[ mp[t][i] ] ){
st_can[ mp[t][i] ] = 1; //标记从终点可以到达的点
q.push(mp[t][i]);
}
}
}
void bfs_beg(){
queue<int> q;
q.push(e);
while (q.size())
{
int t = q.front();
q.pop();
rep(i, 0, mp[t].size())
if ( st[mp[t][i]] )
{
q.push( mp[t][i] );
st[mp[t][i]] = 0;
dist[mp[t][i]] = dist[t] + 1;
}
}
}
int main(){
cin >> n >> m;
while(m--){
int u,v;
cin >> u >> v;
if( u == v ) continue;//去除自环
mp[v].push_back( u );
}
cin >> s >> e;
bfs_end();
memcpy( st , st_can , sizeof st_can );
//注意这里最好有第二个数组标记,在一个数组里删点有后效型。
//如果一个点开始被标记,它通过一个序号比它小的点删除了。
//那么访问到它的时候,就会被当成开始就没被标记的点,会通过它把合法点删除。
rep( i , 1 , n+1 )
if( !st_can[i] ){
rep( j , 0 , mp[i].size() )
if( st[ mp[i][j] ] ) st[ mp[i][j] ] = 0;
//当一个点有其他不能到终点的点时,删去该点。
}
bfs_beg();
if( dist[s] == 0 ) cout << -1;
else cout << dist[s];
return 0;
}