算法笔记.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. 可以处理自环、重边、负环、允许边权为负。
相关推荐
山北雨夜漫步16 分钟前
机器学习 Day14 XGboost(极端梯度提升树)算法
人工智能·算法·机器学习
到底怎么取名字不会重复18 分钟前
Day10——LeetCode15&560
c++·算法·leetcode·哈希算法·散列表
宁酱醇25 分钟前
各种各样的bug合集
开发语言·笔记·python·gitlab·bug
DKPT27 分钟前
正则表达式
java·数据库·笔记·学习·正则表达式
chuxinweihui1 小时前
数据结构——二叉树,堆
c语言·开发语言·数据结构·学习·算法·链表
zhuyixiangyyds1 小时前
day36图像处理OpenCV
图像处理·笔记·学习
Mr__Miss1 小时前
JVM学习笔记
jvm·笔记·学习
freexyn1 小时前
Matlab自学笔记五十一:(推荐)输入参数的数量和可变数量的输入
笔记·算法·matlab
陈大大陈1 小时前
基于 C++ 的用户认证系统开发:从注册登录到Redis 缓存优化
java·linux·开发语言·数据结构·c++·算法·缓存
看到我,请让我去学习1 小时前
C语言基础(day0424)
c语言·开发语言·数据结构