看到还没人用Bellman-Ford过,赶紧水一发

lz非常弱,求各位大佬轻喷qwq

洛谷题目传送门:P3371

0.“松弛”操作

如果存在一条边\((u,v)\)通过中继的方式可以让起点到\(v\)的距离缩短,那么就通过中继点缩短这个距离。

举个栗子:

(用数组\(dis[]\)来表示起点到每个点的距离,以下同样)

一开始,\(dis[2]=1000\),\(dis[3]=2\)(默认起点为1,以下同样)

通过3中继明显比从1直接到2要短,于是我们把\(dis[2]\)更新为\(dis[3]+3=5\)(从起点到3再到5)

于是你理解了什么是松弛

1.Bellman-Ford

Bellman-Ford的思想是用每条边进行松弛,每条边松弛\(n-1\)次,就一定能求出起点到每个点的距离

(如果你能感性理解你就不用看下面了)

为什么?因为每松弛1轮(我们管用每条边都松弛一次叫一轮),最短路就至少“生长”1个点。

再举个例子:

这是个很美丽的有向图。

最开始,除了\(dis[1]\)之外,其他所有\(dis\)都是无穷大。(到不了距离不就是无穷大嘛)。

第1轮松弛:

\(dis[1]=0\)(自己到自己距离肯定是0)

\(dis[2]=min(dis[2],dis[1]+1)=min(INF,1)=1\)

\(dis[3]=min(dis[3],dis[1]+5)=min(INF,1)=1\)

(由于边的顺序问题,松弛出来的结果可能不太一样)

(最坏情况可能只松弛1层)

(现在你明白“生长”是什么意思了吗)

第2轮松弛:

\(dis[4]=min(dis[4],dis[2]+2)=min(INF,3)=3\)

第3轮松弛:

\(dis[3]=min(dis[3],dis[4]+1)=min(5,4)=4\)

正好松弛了\(n-1\)轮。

因为,一个图最多有\(n-1\)层:例如,\(1->2->3->...->n\),这个图(最坏情况)就正好要松弛\(n-1\)轮。

于是你理解了Bellman-Ford。

Code:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define INF 0x7fffffff
struct edge{
int u,v,w;
edge(){u=v=w=0;}
};
edge g[MAXN],cnt;
int n,m,s,dis[MAXN];
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[i].u=u;
g[i].v=v;
g[i].w=w;//存边
}
fill(dis+1,dis+1+n,INF);
dis[s]=0;
for(int i=1;i<=n-1;i++){//松弛n-1轮
for(int j=1;j<=m;j++){
int u=g[j].u,v=g[j].v,w=g[j].w;
if(dis[u]==INF){continue;}//如果当前边的起点到不了那就没法松弛
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
}
}
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}

一交,70pts,所以还要优化。

3.优化

但是,很多情况根本不用松弛\(n-1\)轮。

如果松弛到中间一轮松弛不动了(也就是\(dis\)不变了),那么以后再怎么松弛也不会变(因为已经求出最优解了),为什么可以思考一下。(其实就是我懒得写了233)

AC Code:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define INF 0x7fffffff
struct edge{
int u,v,w;
edge(){u=v=w=0;}
};
edge g[MAXN],cnt;
int n,m,s,dis[MAXN];
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
g[i].u=u;
g[i].v=v;
g[i].w=w;
}
fill(dis+1,dis+1+n,INF);
dis[s]=0;
for(int i=1;i<=n-1;i++){
bool flag=true;
for(int j=1;j<=m;j++){
int u=g[j].u,v=g[j].v,w=g[j].w;
if(dis[u]==INF){continue;}
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
flag=false;
}
}
if(flag){
break;//如果没有松弛过那就没必要再松弛了
}
}
for(int i=1;i<=n;i++){
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}

4.时间复杂度

最坏情况\(O(nm)\),最好情况\(O(m)\)(但是只有RP爆表的情况下才会达到),非常离谱。如果不是因为数据水 人品好玄学原因,几乎一定会TLE。

还有一种Bellman-Ford优化,叫SPFA已死。所以,我建议在座的各位dalao先学Bellman-Ford再学SPFA

SPFA的最坏情况\(O(nm)\),最好情况\(O(m)\),但是除非故意卡(非常容易被卡!),一般都是\(O(m)\)

SPFA留着以后再讲吧,LZ要去吃饭了。

Bellman-Ford算法 例题:P3371 单源最短路径的更多相关文章

  1. SPFA板子 (背景:Luogu P3371 单源最短路径)

    Luogu P3371 单源最短路径 题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数 ...

  2. 【算法导论】单源最短路径之Dijkstra算法

    Dijkstra算法解决了有向图上带正权值的单源最短路径问题,其运行时间要比Bellman-Ford算法低,但适用范围比Bellman-Ford算法窄. 迪杰斯特拉提出的按路径长度递增次序来产生源点到 ...

  3. 【算法导论】单源最短路径之Bellman-Ford算法

    单源最短路径指的是从一个顶点到其它顶点的具有最小权值的路径.我们之前提到的广度优先搜索算法就是一种无权图上执行的最短路径算法,即在所有的边都具有单位权值的图的一种算法.单源最短路径算法可以解决图中任意 ...

  4. 经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)

    哈夫曼编码与哈夫曼算法 哈弗曼编码的目的是,如何用更短的bit来编码数据. 通过变长编码压缩编码长度.我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit.但在很多情况下,数 ...

  5. 洛谷P3371单源最短路径SPFA算法

    SPFA同样是一种基于贪心的算法,看过之前一篇blog的读者应该可以发现,SPFA和堆优化版的Dijkstra如此的相似,没错,但SPFA有一优点是Dijkstra没有的,就是它可以处理负边的情况. ...

  6. 【luogu P3371 单源最短路径】 模板 SPFA

    题目链接:https://www.luogu.org/problemnew/show/P3371 我永远都喜欢Flyod.dijkstra + heap.SPFA #include <cstdi ...

  7. 【luogu P3371 单源最短路径】 模板 dij + heap

    题目链接:https://www.luogu.org/problemnew/show/P3371#sub 堆优化迪杰斯特拉,留着以后复习用 #include <iostream> #inc ...

  8. 洛谷P3371单源最短路径Dijkstra版(链式前向星处理)

    首先讲解一下链式前向星是什么.简单的来说就是用一个数组(用结构体来表示多个量)来存一张图,每一条边的出结点的编号都指向这条边同一出结点的另一个编号(怎么这么的绕) 如下面的程序就是存链式前向星.(不用 ...

  9. luogu p3371 单源最短路径(dijkstral

    本来我写的对的 我就多手写了个 ios::sync_with_stdio(false); 我程序里面用了cin 还有scanf 本来想偷偷懒 我就说 我查了半天错 根本找不到的啊... 后来交了几次 ...

随机推荐

  1. PHP date_isodate_set() 函数

    ------------恢复内容开始------------ 实例 设置 2013 年第 5 周的 ISO 日期: <?php$date=date_create();date_isodate_s ...

  2. PHP fmod() 函数

    实例 返回 x/y 的浮点数余数: <?php$x = 7;$y = 2;$result = fmod($x,$y);echo $result;// $result equals 1, beca ...

  3. linux的文件系统管理(ext4-tune2fs-e2fsck-xfs文件系统)

    文件系统管理 文件系统是Linux系统存放文件的空间.文件系统的类型有很多种,CentOS支持多种文件系统,目前常用的是ext4和xfs文件系统.我们以ext4文件系统为例来说明对文件系统的管理. U ...

  4. Linux下运行windows 系统下编辑的Python脚本显示“: 没有那个文件或目录”的过程及解决方案

    今天在 linux 系统下执行一windows下编辑的python脚本,提示(:没有那个文件或目录)英文提示:(:No such file of directory)如下: 查看文件的权限发现并没有问 ...

  5. 使用docker安装nginx并配置端口转发

    使用docker安装并运行nginx命令: docker run --name=nginx -p 80:80 -d docker.io/nginx 使用命令: docker exec -it ngin ...

  6. 解惑4:java是值传递还是引用传递

    一.概述 曾经纠结了很久java的参数传递方式是什么样的,后面粗略的了解了一鳞半爪以后有了大概的印象:"传参数就是值传递,传对象就是引用传递",后面进一步查找了相关资料和文章以后, ...

  7. Python编程的10个经典错误及解决办法

    接触了很多Python爱好者,有初学者,亦有转行人.不论大家学习Python的目的是什么,总之,学习Python前期写出来的代码不报错就是极好的.下面,严小样儿为大家罗列出Python3十大经典错误及 ...

  8. GitLab 数据库

    访问 GitLab 数据库 步骤 用的 Docker Gitlab,首先进入容器 docker exec -it gitlab /bin/bash `` 找到数据库配置文件 ```bash /var/ ...

  9. 谈下APP测试和WEB测试的区别

    先来讲下相同点: 1.都需要理论知识,相同的用例设计方法:边界值,等价类,错误推导法,场景法 2.同样的测试方法 验证功能是否满足需求 3.都需要检查UI  界面设计是否合理 4.性能检测  并发 吞 ...

  10. java目前常用的几种定时任务

    java目前常用的几种定时任务 JDK自带的Timer spring的Task Quartz elastic-job分布式定时任务 一.JDK自带的Timer Timer是jdk中提供的一个定时器工具 ...