看到还没人用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. 3.29省选模拟赛 除法与取模 dp+组合计数

    LINK:除法与取模 鬼题.不过50分很好写.考虑不带除法的时候 其实是一个dp的组合计数. 考虑带除法的时候需要状压一下除法操作. 因为除法操作是不受x的大小影响的 所以要状压这个除法操作. 直接采 ...

  2. Android运行时注入浅析与使用

    背景 最近接触新项目,项目中引入了Android Annotation(AA)依赖注入开源框架,代码中大片的注解代码,对于没用过注解框架(或者说没有如此大面积的使用)的我来说确实看得很费力,于是花时间 ...

  3. 【NOIP2016】组合数问题 题解(组合数学+递推)

    题目链接 题目大意:给定$n,m,k$,求满足$k|C_i^j$的$C_i^j$的个数.$(0\leq i\leq n,1\leq j\leq \min(i,m))$. --------------- ...

  4. 自定义 Mybatis 框架

    分析流程 1. 引入dom4j <dependencies> <!--<dependency> <groupId>org.mybatis</groupI ...

  5. CSS高级特效(上)

    1.CSS Shapes CSS Shapes是一个新标准,旨在让Web设计者能使用各种形状. CSS Shapes包含两组新属性,一组用于设置影响盒子中内容的形状,另一组用于设置影响形状元素周边内容 ...

  6. dom4j解析xml时报出文件提前结束

    在写javaweb小项目的时候,用dom4j解析xml报出如下错误: org.dom4j.DocumentException:Error    .......    Nested exception: ...

  7. java流程控制语句switch

    switch 条件语句也是一种很常用的选择语句,它和if条件语句不同,它只能针对某个表达 式的值作出判断,从而决定程序执行哪一段代码. 格式: switch (表达式){ case 目标值1: 执行语 ...

  8. Windows下,配置VS Code的Java开发环境

    Windows下,配置VS Code的Java开发环境 前言 最近痴迷于VS Code的开发环境配置,原因就在于它的轻巧和免费,还能当一个非常棒的文本编辑器.如果之前你配置过VS Code并且失败了, ...

  9. LeetCode343 整数拆分详解

    题目详情 给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化. 返回你可以获得的最大乘积. 示例 1: 输入: 2 输出: 1 解释: 2 = 1 + 1, 1 × 1 = 1 ...

  10. angular中a标签带请求头下载excel

    <!DOCTYPE html> <html lang="en" ng-app="app"> <head> <meta ...