(洛谷 2296)寻找道路#spfa#

Thank you for mr_wuyongcong’s help

题目描述:

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

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

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

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

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

分析

首先,就是要找出不能到终点的点,然后再除了起点外,通向这些点这些点作废


代码

#include <cstdio>
using namespace std;
struct q{
    int x,y,next;
}a[200001],b[200001];
int n,m,t,ls[10001],list[10001],en,st;
bool vv[10001],v[10001]; long long d[10001];
void fspfa(int stu){
    int head=0,tail=1;
    list[1]=stu;
    do{
    	head++;
    	if (head>n) head=1;
    	t=d[list[head]];
    	while (t>0){
    		if (!vv[b[t].y]){
    		tail++;
    		if (tail>n) tail=1;
    		vv[b[t].y]=1;//标记可走路
            list[tail]=b[t].y;
            }
    		t=b[t].next;
    	}
    }while (head!=tail); 
}
bool pd(int t){
    while (t>0){
        if (!vv[a[t].y]) return false;//如果出边到不了终点点作废
        t=a[t].next;
    } return true;
}
void spfa(int st){
    int head=0,tail=1;
    for (int i=1;i<=n;i++) d[i]=2147483647;
    list[1]=st; v[st]=1; d[st]=0;
    do{
        head++;
        if (head>n) head=1;
        t=ls[list[head]];
        while (t>0){
            if ((long long)d[a[t].x]+1<d[a[t].y]&&pd(ls[a[t].y])){
                d[a[t].y]=d[a[t].x]+1;
                if (!v[a[t].y]){
                    v[a[t].y]=1;
                    tail++;
                    if (tail>n) tail=1;
                    list[tail]=a[t].y;
                }
            }
            t=a[t].next;
        }
        v[list[head]]=0;
    }while (head!=tail);
    if (d[en]==2147483647) printf("-1");
    else printf("%d",d[en]);
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++){//邻接表
        scanf("%d%d",&a[i].x,&a[i].y);
        a[i].next=ls[a[i].x];
        ls[a[i].x]=i;
        b[i].x=a[i].y;
        b[i].y=a[i].x;
        b[i].next=d[b[i].x];
        d[b[i].x]=i;
    } scanf("%d%d",&st,&en); vv[en]=1;
    fspfa(en);//从终点找  spfa(st);//正常spfa
    return 0;
}

#最后重申(head!=tail)是因为循环队列

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值