在有向图 (G) 中,每条边的长度均为 (1),现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:
- 路径上的所有点的出边所指向的点都直接或间接与终点连通。
- 在满足条件 (1) 的情况下使路径最短。
注意:图 GG 中可能存在重边和自环,题目保证终点没有出边。
请你输出符合条件的路径的长度。
这道题,我们考虑哪些点能够到达终点,问题等价于:反向建边后,终点能到达哪些点。
void dfs(int x){
h[x]=true;
for(auto i:E[x])
if(!h[i])dfs(i);
}
(E) 正是反向建边后的边集。
(h_x=1) 就表示 (x) 号点能到终点。
所以,我们可以判断哪些点可以走了。
能经过的点要满足 (2) 个条件:
- 它自己能到达终点
- 它的出边所指向的点都能达到终点
for(int i=1;i<=n;i++)
if(h[i]){
dis[i]=true;
for(auto j:v[i])
if(!h[j]){dis[i]=false;break;}
}
这部做完了,就可以开始 (bfs) 了。
边权全都是 (1) 自然是第 (1) 次搜到的就是最优解。
q.push((node){s,0});
while(q.size()){
node x=q.front();
if(x.x==t){
cout<<x.s;
return 0;
}
for(auto i:v[x.x])
if(dis[i]&&!vis[i]){
vis[i]=true;
q.push((node){i,x.s+1});
}
q.pop();
}cout<<-1;
还是很简单的。
总代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
struct node{
int x,s;
};
bool h[10010],vis[10010];
int n,m,dis[10010],s,t;
vector<int>v[10010];
vector<int>E[10010];
queue<node>q;
void dfs(int x){
h[x]=true;
for(auto i:E[x])
if(!h[i])dfs(i);
}
int main(){
read(n);read(m);
for(int i=1;i<=m;i++){
int x,y;read(x);read(y);
v[x].push_back(y);
E[y].push_back(x);
}
read(s);read(t);
dfs(t);
for(int i=1;i<=n;i++)
if(h[i]){
dis[i]=true;
for(auto j:v[i])
if(!h[j]){dis[i]=false;break;}
}
q.push((node){s,0});
while(q.size()){
node x=q.front();
if(x.x==t){
cout<<x.s;
return 0;
}
for(auto i:v[x.x])
if(dis[i]&&!vis[i]){
vis[i]=true;
q.push((node){i,x.s+1});
}
q.pop();
}cout<<-1;
return 0;
}