算法笔记.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. 可以处理自环、重边、负环、允许边权为负。
相关推荐
疯狂打码的少年7 分钟前
【计算机网络】子网掩码与子网划分计算(含CIDR表示法)
服务器·笔记·计算机网络·php
Msshu12320 分钟前
2~5串锂电快充优选|XSP36 Type‑C升压/升降压快充管理芯片
数据结构·随机森林·贪心算法·排序算法·线性回归·启发式算法
shirsl1 小时前
算法 Day 2 滑动窗口 + 栈 / 单调栈
开发语言·python·算法
自小吃多2 小时前
PCB Editor软件复制、改变、删除操作笔记
笔记·嵌入式硬件
土司大王2 小时前
LeetCode hot100 回溯专题总结:Java 通用模板、决策树模型
java·算法·leetcode·决策树
2601_962218612 小时前
万象生鲜系统订单全生命周期状态同步技术实现业务可视
大数据·数据库·人工智能·python·算法
那年窗外下的雪.2 小时前
AIDC 学习日志|第 22 天|All-Active/Single-Active 故障演练设计
服务器·网络·学习·算法·哈希算法
wzdark3 小时前
基于启发式搜索的最优路径规划算法研究4
算法
动词ing3 小时前
【学习笔记】数据结构栈与队列(栈先进后出+队列先进先出+括号匹配+消消乐模型)
数据结构·笔记·学习
l1t3 小时前
用superpi、tinypi、tpi等工具计算圆周率的比较
c语言·算法