算法知识:bfs(图的遍历),单源最短路径
牛客16498寻找道路题解
题目大意,给定一个n个点和m条边的有向图,求一条从起点到终点最短路径,要求路径上所有的点直接或者间接与终点相连。(每条边边权为1),图中可能有自环或者重边
例如图中的点2,因为其所指向的点6没有与终点5建立关系,所以不能够在最短路径考虑范围内(尽管1->2->5距离是该图中,起点到终点的最短路径)
这种情况最短路径是,1->3->4->5,距离为3
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=1e4+5;
vector<int> G[maxn];//用来表示每个点存储的边
int vis1[maxn];//两遍bfs分别用到的标记数组
int vis2[maxn];
int s,t;//起点和终点
int n,m;
queue<int> q;
int dis[maxn];//记录最短距离
int main ()
{
memset(dis,0,sizeof(dis));
scanf ("%d %d",&n,&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf ("%d %d",&x,&y);
if (x==y) continue;//如果出现自环则跳过
G[y].push_back(x);//原本是从x指向y的一条边,现在将边反向预处理,用来后面从终点向起点开始bfs的处理
}
scanf ("%d %d",&s,&t);
vis1[t]=1;
q.push(t);//从终点开始遍历,标记路径上所有的点
while (!q.empty())
{
int now=q.front();
q.pop();
for (int i=0;i<G[now].size();i++){
if (!vis1[G[now][i]]){
vis1[G[now][i]]=1;
q.push(G[now][i]);
}
}
}
//vis1这个标记数组已经处理好了从终点能够遍历到的点
//vis2用来清理不合法的点
memcpy(vis2,vis1,sizeof(vis2));
for (int i=1;i<=n;i++){
if (!vis1[i]){//未被标记,说明该点与终点没有直接或者间接关系
for (int j=0;j<G[i].size();j++){
if( vis2[G[i][j]]){//但是与该点相连的边跟终点有关系,还是得清除,不合题意
vis2[G[i][j]]=0;
}
}
}
}
//两遍标记,已经处理好了所有的合法点,所以我们再次bfs求最短路径即可
q.push(t);
dis[t]=0;
while (!q.empty())
{
int now=q.front();
q.pop();
for( int i=0;i<G[now].size();i++){
if (vis2[G[now][i]]){
vis2[G[now][i]]=0;
q.push(G[now][i]);
dis[G[now][i]]=dis[now]+1;
}
}
}
if( dis[s]==0){
printf("-1\n");
}else {
printf("%d\n",dis[s]);
}
return 0;
}