Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法。
输入:带权图
输出:从第0个点到其他点的最短路径值
Bellman-Ford 算法描述:
- 创建源顶点 v 到图中所有顶点的距离的集合 distSet,为图中的所有顶点指定一个距离值,初始均为 Infinite,源顶点距离为 0;
- 计算最短路径,执行 V – 1 次遍历;
- 对于图中的每条边:如果起点 u 的距离 d 加上边的权值 w 小于终点 v 的距离 d,则更新终点 v 的距离值 d;
- 检测图中是否有负权边形成了环,遍历图中的所有边,计算 u 至 v 的距离,如果对于 v 存在更小的距离,则说明存在环
源码如下:
/*
带权值图的一种表示方法:顶点与和向边数组
*/
public class DigraphVEW {
String[] vertex;//所有顶点的数组,存放顶点的名字
int verNum;//顶点个数
Edge[] edgds;//所有带权边的数组
public DigraphVEW(String[] vertex, Edge[] edgds) {
this.vertex = vertex;
this.verNum = vertex.length;
this.edgds = edgds;
}
public String[] getVertex() {
return vertex;
}
public void setVertex(String[] vertex) {
this.vertex = vertex;
}
public int getVerNum() {
return verNum;
}
public Edge[] getEdgds() {
return edgds;
}
public void setEdgds(Edge[] edgds) {
this.edgds = edgds;
}
public static class Edge{
int start;
int end;
int weight;
public Edge(int start, int end, int weight) {
this.start = start;
this.end = end;
this.weight = weight;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getEnd() {
return end;
}
public void setEnd(int end) {
this.end = end;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
}
import java.util.Arrays;
/*
单源最小路径算法,给出从一个点到其他所有点的最小路径
*/
public class BellMan {
int[] minPaths; //记录从源点到所有其他点的最短路径
DigraphVEW di; //带权值的图
int INF= 65535; //带表正无穷
/*
初始化
*/
public BellMan(DigraphVEW di) {
this.minPaths = new int[di.getVerNum()];
this.di = di;
Arrays.fill(minPaths,INF);
minPaths[0] = 0;
}
public boolean bellManMinPath(){
//如有n个顶点,最大遍历n-1次
boolean isFinished = true; //标识是否完成松驰,如果某次迭代后,所有点最小路径数据没变,则认为完成了。
for (int i = 1; i < di.getVerNum(); i++) {
for (DigraphVEW.Edge edge: di.getEdgds()) {
if (edge.weight + minPaths[edge.start] < minPaths[edge.end]) {
minPaths[edge.end] = edge.weight + minPaths[edge.start];
isFinished = false;
}
}
if (isFinished) {
break;
}
}
for (DigraphVEW.Edge edge: di.getEdgds()) {
if (edge.weight + minPaths[edge.start] < minPaths[edge.end]) {
return false;
}
}
return true;
}
public int[] getMinPaths() {
return minPaths;
}
}
测试代码如下:针对以下两种情况
@Test
public void bellManMinPath() {
String[] vertexs = new String[]{"A","B","C","D"};
DigraphVEW.Edge[] edges = new DigraphVEW.Edge[]{
new DigraphVEW.Edge(0,1,1),
new DigraphVEW.Edge(0,2,2),
new DigraphVEW.Edge(1,2,2),
new DigraphVEW.Edge(1,3,6),
new DigraphVEW.Edge(2,3,3)
};
DigraphVEW di = new DigraphVEW(vertexs,edges);
BellMan bellMan= new BellMan(di);
boolean result = bellMan.bellManMinPath();
assertEquals(true ,result);
assertArrayEquals(new int[]{0,1,2,5},bellMan.getMinPaths());
}
@Test
public void bellManMinPathFailed() {
String[] vertexs = new String[]{"A","B","C","D"};
DigraphVEW.Edge[] edges = new DigraphVEW.Edge[]{
new DigraphVEW.Edge(0,1,1),
new DigraphVEW.Edge(0,2,2),
new DigraphVEW.Edge(1,2,2),
new DigraphVEW.Edge(1,3,6),
new DigraphVEW.Edge(2,3,3),
new DigraphVEW.Edge(2,0,-5),
};
DigraphVEW di = new DigraphVEW(vertexs,edges);
BellMan bellMan= new BellMan(di);
boolean result = bellMan.bellManMinPath();
assertEquals(false ,result);
}