图解Bellman-Ford算法

Bellman-Ford算法:
为了能够求解边上带有负值的单源最短路径问题,Bellman(贝尔曼)和Ford(福特)提出了从源点逐次绕过其他顶点,以缩短到达终点的最短路径长度的方法。


[img]http://dl.iteye.com/upload/attachment/0076/0621/e2977195-d3bb-34bb-b4aa-168452a7ff26.gif[/img]

[img]http://dl.iteye.com/upload/attachment/0076/0623/cb0de48b-94a7-38cc-a10b-d8d86ac0940e.gif[/img]


[img]http://dl.iteye.com/upload/attachment/0076/0629/54aed835-0128-3cad-a66c-2561d46460cb.gif[/img]

[img]http://dl.iteye.com/upload/attachment/0076/0637/7c2828d7-5f20-38c4-b929-1b3217004b5e.gif[/img]

Bellman-ford算法是求解连通带权图中单源最短路径的一种算法,它允许图中存在权值为负的边。同时它还能够判断出图中是否存在一个权值之和为负的回路。如果存在的话,图中就不存在最短路径(因为,假设存在最短路径的话,那么我们只要将这条最短路径沿着权值为负的环路再绕一圈,那么这条最短路径的权值就会减少了,所以不存在最短的路径,因为路径的最小值为负无穷),如果不存在的话,那么求出源点到所有节点的最短路径。


Bellman-Ford算法主要是针对有负权值的图。来判断该图中是否有负回路,或者存在最短路径的点。判断的思路,从源点出发,进行n - 1(n为顶点数)遍历,在每次的遍历过程中,对所有的边进行遍历判断,同样是利用松弛计算的思想,dis[v] > dis[u] + w(u, v)不断更新dis数组的值,直到循环结束。然后就是这个算法最精彩的地方了,再对所有的边进行一次遍历,看是否存在dis[v] > dis[u] + w(u, v)的边,若存在,则返回FALSE,说明图中存在负回路;若不存在,则返回TRUE,dis数组记录的就是每一个点到源点的最小值。


例:求如图中A点到各点的最短距离

[img]http://dl.iteye.com/upload/attachment/0076/0632/a6aeda84-635c-3f07-a7be-e96f77de9286.gif[/img]
  
/**
* 采用保存边的方式来存储图的的信息。
* p保存的是前驱节点,d保存的是源点到每一个点的最短距离。我们最后又做了一次判断,如果还有可以松弛
* 的边,那么可以保证的是图中有负权的环存在,这样的话就没有最短路径只说了,可以无限小。
*
* @author daijope
*
*/
public class BellmanFord {
private static final int m = 10000;
public static void main(String[] args) {

Adge a1 = new Adge(0, 1, -1);
Adge a2 = new Adge(0, 2, 4);
Adge a3 = new Adge(1, 2, 3);
Adge a4 = new Adge(3, 1, 1);
Adge a5 = new Adge(1, 3, 2);
Adge a6 = new Adge(3, 2, 5);
Adge a7 = new Adge(1, 4, 2);
Adge a8 = new Adge(4, 3, -3);
Adge[] as = new Adge[]{a1, a2, a3, a4, a5, a6, a7, a8};

int[] d = new int[5];
int[] p = new int[5];
d[0] = 0;
p[0] = 0;
for (int i = 1; i < d.length; i++) {
d[i] = m;
p[i] = -1;
}
bellman_Ford(as, d, p);

for (int i = 0; i < d.length; i++) {
System.out.println(d[i]);
}
}
private static void bellman_Ford(Adge[] as, int[] d, int[] p){
for(int i = 1; i < d.length; i++) {
for (int j = 0; j < as.length; j++) {
if (d[as[j].getV()] > d[as[j].getU()] + as[j].getW()) {
d[as[j].getV()] = d[as[j].getU()] + as[j].getW();
p[as[j].getV()] = as[j].getU();
}
}
}
for (int j = 0; j < as.length; j++) {
if (d[as[j].getV()] > d[as[j].getU()] + as[j].getW()) {
System.out.println("有负环");
}
}


}
}
class Adge {
private int u;
private int v;
private int w;

public Adge(int u, int v, int w) {
this.u = u;
this.v = v;
this.w = w;
}

public int getU() {
return u;
}

public void setU(int u) {
this.u = u;
}

public int getV() {
return v;
}

public void setV(int v) {
this.v = v;
}

public int getW() {
return w;
}

public void setW(int w) {
this.w = w;
}


}


运行:
C:\java>java BellmanFord
0
-1
2
-2
1

下载源码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值