在写这个之前我一定要安利一个网站:programiz
首先介绍Bellma-Ford算法的用处,与Dijkstra算法不一样的是他能处理负圈的情况,也就是圈中有权重是负数的情况。
在此之前,我一直不懂为啥求一个最短路怎么会有权重为负数的情况,看了这篇文章后,真的是大开眼见。主要是前面看的博客都没有回答这个问题,到是有一个博主给了这个链接,然后我点进去第二段就是解释了这个问题。
好了回到正题:负圈或者负权重的意义?
对于求解最短路中这个字面意思确实很难看出有什么作用,但是图是一种数据结构,是可以描绘真实世界的工具,自然肯定不仅仅是用来描述两个地点之间的距离的。比如,现金流动,化学反应中的热量的吸收和释放等。
所以可以看出这些东西就可以将最短路算法应用在这些求解最优方式上,如果解决了负圈问题,那么这些计算就会有很大的突破。
那么回答了负圈的意义后,接下来正式介绍这种算法:
首先我们要有一个数据结构储存边的关系,这里我们用一个结构体来储存:
struct edge{
int from;
int to;
int cost;
};
然后定义一个状态
d
[
i
]
:
=
d[i]:=
d[i]:=从起点s到节点i的最短距离。
所以有了下面的递推式子:
d
[
i
]
=
m
i
n
{
d
[
j
]
+
(
从
i
到
j
的
边
的
权
重
)
∣
e
=
(
i
,
j
)
∈
E
}
d[i]=min\{d[j]+(从i到j的边的权重)| e=(i,j)\in E\}
d[i]=min{d[j]+(从i到j的边的权重)∣e=(i,j)∈E}
那么我们可以知道最初的状态就是
d
[
s
]
=
0
d[s]=0
d[s]=0,
d
[
i
]
=
I
N
F
d[i]=INF
d[i]=INF。
那么我们更新的条件就可以得到:
if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost){
d[e.to]=d[e.from]+e.cost;
}
这里我们可以看到的是有一个限制条件是
d
[
e
.
f
r
o
m
]
!
=
I
N
F
d[e.from]!=INF
d[e.from]!=INF
所以可以保证所有的递推是从s这个点出来的。
而这样就可以保证在 ∣ V ∣ − 1 |V|-1 ∣V∣−1次迭代后找出每一个 d [ i ] d[i] d[i]的最小值。至于为什么是V-1次可以理解为有一条路是必须从s出发然后经过每一个点后才能推到这个点。
那么说了这么多可能还是有些懵,所以就直接看代码吧!
struct edge{
int from,to,cost;
}es[MAX_E]
int d[MAX_V];
int V,E;
void shortest_path(int s){
for(int i=0;i<V;++i) d[i]=INF;
d[s]=0;
while(true){
bool update=false;
for(int i=0;i<E;++i){
edge e=es[i];
if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost){
d[e.to]=d[e.from]+e.cost;
update=true;
}
}
if(!update) break;
}
}