codevs 寻找道路

点击就送屠龙宝刀

题目描述 Description

在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找一条从起点到终点的路径,该路径满足以下条件:

1.路径上的所有点的出边所指向的点都直接或间接与终点连通。

2.在满足条件1的情况下使路径最短。

注意:图G中可能存在重边和自环,题目保证终点没有出边。

请你输出符合条件的路径的长度。

输入描述 Input Description

第一行有两个用一个空格隔开的整数n和m,表示图有n个点和m条边。

接下来的m行每行2个整数x、y,之间用一个空格隔开,表示有一条边从点x指向点y。

最后一行有两个用一个空格隔开的整数s、t,表示起点为s,终点为t。

输出描述 Output Description

输出文件名为road.out。

输出只有一行,包含一个整数,表示满足题目描述的最短路径的长度。如果这样的路径不存在,输出-1。
样例输入 Sample Input

road.in

3 2

1 2

2 1

1 3
road.out

-1
这里写图片描述
样例输出 Sample Output

road.in

6 6

1 2

1 3

2 6

2 5

4 5

3 4

1 5

road.out
3
这里写图片描述

数据范围及提示 Data Size & Hint

对于30%的数据,0< n ≤10,0< m ≤20;

对于60%的数据,0< n ≤100,0< m ≤2000;

对于100%的数据,0< n ≤10,000,0< m ≤200,000,0< x,y,s,t≤n,x≠t。

这道题比较水,做法也比较多。第一种做法就是两边bfs。第二种是一边bfs一边dfs。第三种是从终点dfs一边记录所有能到达终点的点,然后就得到了不能到达终点的点然后跑spfa就可以了。

#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>

using namespace std;

vector<int> a[10001];
vector<int> b[10001];
queue<int> q;
bool pd[10001];
int now,i,j,n,m,x,y,s,t,jb,fuck;
int jl[10001];
queue<int> dl;

void bfs()
{
while (!q.empty()){
    now=q.front();
    q.pop();
    for (j=0;j<b[now].size();j++) if (!pd[b[now][j]]){
    pd[b[now][j]]=true;
    q.push(b[now][j]);
    }
    }
}

void spfa()
{
    while (!dl.empty()){
    now=dl.front();
    dl.pop();
    for (i=0;i<a[now].size();i++) {
    jb=jl[now]+1;
    if (jb<jl[a[now][i]] && pd[a[now][i]]){
    jl[a[now][i]]=jb;
    dl.push(a[now][i]);
    }
    }
    }
}

int main()
    {
    scanf("%d%d",&n,&m);
    memset(pd,false,sizeof(pd));
    memset(jl,200001,sizeof(jl));
    for (i=1;i<=m;i++){
    scanf("%d%d",&x,&y);
    if (x!=y) {
    a[x].push_back(y);
    b[y].push_back(x);
    }
    }
    scanf("%d%d",&s,&t);
    q.push(t);
    pd[t]=true;
    bfs();
    for (i=1;i<=n;i++) if (!pd[i]) {
    for (j=0;j<b[i].size();j++) q.push(b[i][j]);
    }
    while (!q.empty()){
    fuck=q.front();
    q.pop();
    pd[fuck]=false;
    }
    dl.push(s);
    jl[s]=0;
    spfa();
    if (jl[t]==1094795585) printf("-1");
    else printf("%d",jl[t]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值