牛客NC16498寻找道路题解

算法知识: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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值