算法笔记.spfa算法(bellman-ford算法的改进)

题目:(来源于AcWing)

给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环, 边权可能为负数。

请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 impossible。

数据保证不存在负权回路。

输入格式

第一行包含整数 n 和 m。

接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。

输出格式

输出一个整数,表示 1 号点到 n 号点的最短距离。

如果路径不存在,则输出 impossible。

数据范围

1≤n,m≤105,

图中涉及边长绝对值均不超过 10000。

输入样例:
复制代码
3 3
1 2 5
2 3 -3
1 3 4
输出样例:
复制代码
2

改进思路:

我们发现,只有一个节点的最短路径被更新之后,这个节点才可能被用来继续更新其出边的节点的最短路径。

代码实现:

cpp 复制代码
#include<iostream>
#include<algorithm>
using namespace std;
#include<queue>
int n,m;
const int N = 100010;
int h[N],e[N],ne[N],w[N],idx;
int dist[N];
bool exi[N];//存储队列中是否已经有这个点了

void add(int a,int b,int c)
{
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

int spfa()
{
    
    queue<int> q;
    q.push(1);
    dist[1] = 0;
    exi[1] = true;
    
    while(q.size())
    {
        int nownode = q.front();
        
        q.pop();
        exi[nownode] = false;//取出该节点后更新exi数组
        //遍历出边
        for(int i = h[nownode];i!=-1;i=ne[i])
        {
            int tempnode = e[i];
            
            if(dist[tempnode] > dist[nownode]+w[i])
            {
                dist[tempnode] = dist[nownode]+w[i];
                if(!exi[tempnode])
                {
                    q.push(tempnode);//只有本节点最短路被更新了,才需要更新这个节点的出边
                    exi[tempnode] =true;
                }
                
            }
        }
    }
    
    if(dist[n] ==0x3f3f3f3f) return 0x3f3f3f3f;
    return dist[n];
}

int main()
{
    fill(h,h+N,-1);//必须在存储边操作前初始化
    fill(dist,dist+N,0x3f3f3f3f);
    idx = 0;
    scanf("%d%d",&n,&m);
    while(m--)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(a,b,c);
    }
    
    int t = spfa();
    if(t == 0x3f3f3f3f)cout <<"impossible"<<endl;
    else cout << t<<endl;
    return 0;
}

细节:

  1. 需要记录队列中是否已经存在该节点,如果已经存在,即便其被更新,也不用再添加它。

  2. 头指针h\[\]要在添加边之前初始化为-1.

spfa算法判断负环:

只需要添加数组count\[\],记录每个节点最短路径,上的边的数量,如果边数>n,说明存在负环。

spfa算法的性能:

  1. 时间复杂度可以为O(n+m),但最坏时退化为O(nm)。
  2. 可以处理自环、重边、负环、允许边权为负。
相关推荐
岑梓铭几秒前
《考研408数据结构》第七章(B树 和 B+树)复习笔记
数据结构·笔记·b树·考研·408
漂流瓶jz1 小时前
UVA-1613 K度图的着色 题解答案代码 算法竞赛入门经典第二版
算法·深度优先·图论·贪心·aoapc·算法竞赛入门经典·uva
Pniubi2 小时前
动态规划入门 ( - 力扣509斐波那契数)
算法·动态规划
吴长建先生重名了3 小时前
GitHub Actions部署报表系统踩坑记:幂等性与限
算法
贝壳6903 小时前
一个2026年2月才上传的库,凭什么敢碰2009年就有人写烂的题目
算法
贝壳6904 小时前
同一道三亿位选型题,三个AI给了我三个答案,我把它们拉进同一台机器复跑
算法
Go Work5 小时前
docker 占满根分区时先分清谁在吃盘
经验分享·笔记
3095566665 小时前
股票接口返回 404 与空数组的排查笔记:证书状态与级别参数
java·笔记·python·ios·iphone·股票数据api·股票数据接口
蒸蒸yyyyzwd6 小时前
从邓明学习的后端笔记
笔记·学习
岑梓铭6 小时前
《考研408数据结构》第八章(排序)复习笔记
数据结构·笔记