图论详解——Bellman-Ford(清晰易懂)

news/2024/7/15 18:23:53 标签: 数据结构, c++, 动态规划, 算法, 图论

开学第一周,晚上属实作业有点乱

于是就拖更了一周


今天我们来讲解一下图论最短路径算法

最简单

最清晰易懂

同时时间复杂度最高的算法

它的时间复杂度能达到O(VE)(点的数量*边的数量)

在学习Bellman-Ford之前,你需要先学会链式前向星

大家可以上网或者其他途径自行查阅一下

  1. 原理

这个算法是对图进行v-1次松弛操作(v为点的数量)

完了?

啊 完了


松弛看不懂没事

继续往下看

正式开始讲原理:

日常建个小图

有没有权值无所谓,没有权值就当作1

假设我们要求1点到5点的最短路径

第一步:把1连接的所有边的目标点更新最短路径路径

最短路径更新成现在这样

现在更新2的

这是可以发现,1到5的路程可以更新了

2+7<10

所以更新

然后剩下的就没什么可更新的了

这样算出来,1到5的最短路程就是9


上面一套流程,就是我们用贝尔曼福特算法的过程

而2+7<10这步,就叫做松弛操作

松弛N-1次,每次都遍历每个点的每条边,能松则松,不能松就不松


没错 贝尔曼福特还是这么简单

但这也造成了他时间复杂度贼高

就比如上图

3的松弛根本没用,也造成了时间上的问题

如果n<=10^6

那浪费的时间不可设想

另外 它还有一个优点

就是能处理负权环

怎么处理呢?

先来看下普通代码

# include <iostream>
# include <cstdio>
# include <cmath>
# include <cstring>
using namespace std;
# define int long long
# define N 10005
# define M 10005
int s,t,n,m,m2;
double f[N];
struct node{
    int x,y;
}a[N];
struct node2{
    int to,next;
    double w;
}e[M];
int adj[N];
void add(int u,int v,double w2){
    m2++;
    e[m2].to=v;
    e[m2].w=w2;
    e[m2].next=adj[u];
    adj[u]=m2;
    return ;
}
void relax(int u,int v,double w2){
    if (f[v]>f[u]+w2){
        f[v]=f[u]+w2;
    }
    return ;
}
void ford(){
    memset(f,0x7f7f,sizeof(f));
    f[s]=0;
    for (int i=1;i<=n-1;i++){
        for (int j=1;j<=n;j++){
            for (int k=adj[j];k;k=e[k].next){
                int l=e[k].to;
                relax(j,l,e[k].w);
            }
        }
    }
    return ;
}
signed main(){
    ford();
    printf("%.2lf",f[t]);
    return 0;
}

本代码编写的是从s到t的最短路径,所以f[i]表示s到i的最短路径


解决下刚才的问题:负权环怎么解决

因为我们是n-1次松弛操作

在这种情况下,保证能把这个图的最短路径求出来

而负权环什么意思?他不可能有最短路径

就是这个样子了

他每绕一圈,路径都-14

所以无限循环求不出

要想检测这种情况

就要松弛n次,如果第n次还有可以能松弛的

那说明就是负权环


有些同学就要问了

f数组不是动态规划里的吗?而且这个松弛操作为什么看上去这么像动态规划的状态转移方程啊?

没错你的直觉是正确的

自己的算法用自己的成就 天经地义()

今天的Bellman-Ford算法的讲解就到这里

如果还有哪些问题或不懂的地方 随时可以评论


http://www.niftyadmin.cn/n/86776.html

相关文章

高精密数字源表的发展史

在半导体、汽车、医疗等高端制造行业&#xff0c;源表通常被用于半导体材料或精密器件的电性能特性测试和生产测试应用&#xff0c;以及中低电平测试和实验室研究使用。源表采用四象限工作模式&#xff0c;可以在提供精密电压、电流源的同时&#xff0c;又能够作为电压、电流、…

10分钟学会使用 Loki 日志聚合系统

Loki 是一个由Grafana Labs 开发的开源日志聚合系统&#xff0c;旨在为云原生架构提供高效的日志处理解决方案。 Loki 通过使用类似 Prometheus 的标签索引机制来存储和查询日志数据&#xff0c;这使得它能够快速地进行分布式查询和聚合&#xff0c;而不需要将所有数据都从存储…

NCUT加权的NMF

矩阵定义 X&#xff1a;特征矩阵&#xff0c;矩阵的维度为体素数mx&#xff08;指标数x被试数&#xff09;n S&#xff1a;相似性矩阵&#xff0c;由特征矩阵的每一行计算皮尔逊相关得到mxm的方阵 D&#xff1a;度矩阵&#xff0c;度矩阵的对角线元素由相似性矩阵S对应的行和…

Android 5.0 Termux 实现对米家设备的控制

1. 获取设备Token 使用 Xiaomi-cloud-tokens-extractor 获取设备token Xiaomi-cloud-tokens-extractor开源地址&#xff1a;https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor 下载代码以及运行 这步可以在当前的电脑上运行&#xff0c;也可以在Termux上运…

ABAP 351 - 动态编程

作为面对对象的编程语言&#xff0c;ABAP也是支持动态编程的。ABAP351作为一门独立的课程介绍了类反射机制如何实现的过程。一、Field SymbolsField Symbols(字段符号)在ABAP编程中经常使用&#xff0c;实际上它具备以下几点特性&#xff1a;字段符号只是字段的一个别名&#x…

LocalDNS

目录 文章目录目录本节实战DNS优化1、dns 5s 超时问题解决办法2、NodeLocal DNSCache实验软件关于我最后本节实战 实战名称&#x1f498; 实战&#xff1a;NodeLocal DNSCache-2022.7.30(测试成功)&#x1f498; 实战&#xff1a;NodeLocal DNSCache-2023.2.21(测试成功) DNS优…

slice和splice区别

slice和splice区别 splice和slice是数组中的两个重要的方法。 slicesplice不会改变原数组改变原数组返回原数组中的部分元素返回原数组中被删除的元素组成的新数组用来选择数组中的元素用于在数组中插入或者删除元素 1.splice的语法 array.splice(index,howmany,item1,…,ite…

浅谈SQL中的union和union all

文章目录概念基础语法使用技巧区别总结概念 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。 UNION 操作符选取不同的值&#xff0c;如果允许得到重复的值&#xff0c;可以使用 UNION ALL 基础语法 -- u…