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

最短路径算法优化
本文介绍了一种在有向图中寻找从起点到终点的最短路径的方法,并确保路径上所有点都能直接或间接到达终点。通过两阶段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)是因为循环队列

### SPFA算法简介 SPFA(Shortest Path Faster Algorithm)是一种用于解决带有负权边的单源最短路径问题的算法[^2]。该算法是对Bellman-Ford算法的一种优化,通过将节点的遍历顺序进行优化,减少了不必要的松弛操作,从而提高了算法的效率。 #### 算法特点 SPFA算法特别适用于处理含有负权边的图以及需要判断负权环的场景[^1]。在最坏的情况下,SPFA算法的时间复杂度和Bellman-Ford算法相同,为O(nm);但在稀疏图上运行效率较高,平均时间为 O(km),其中 k 是一个小于 1 的常数[^3]。 ### SPFA算法的工作原理 SPFA算法的核心在于使用队列来进行优化。具体来说: - 初始化时,将起点加入队列,并设置其距离为0。 - 对于队列中的每一个顶点 u,对其所有的邻接点 v 进行松弛操作。 - 如果通过某条边 (u, v) 可以使 d[v] 减小,则更新 d[v] 并将其入队。 - 若某个顶点被访问次数超过 n 次,则说明存在负权回路。 ### Python 实现示例 以下是Python版本的SPFA算法实现: ```python from collections import deque def spfa(graph, start): dist = {node: float('inf') for node in graph} dist[start] = 0 queue = deque([start]) in_queue = set([start]) while queue: u = queue.popleft() in_queue.remove(u) for v, weight in graph[u]: if dist[u] + weight < dist[v]: dist[v] = dist[u] + weight if v not in in_queue: queue.append(v) in_queue.add(v) return dist ``` 此代码实现了基本的SPFA逻辑,可以计算从指定起始节点到其他各节点之间的最短路径长度[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值