BellmanFord算法
BellmanFord算法的核心思想是:遍历每一条边,如果这条边可以使源点到这条边的终点比源点到这条起点加上这条边的边长变短则松弛成功。
例如上图:首先我们用一个数组进行记录从源点开始到除其本身外顶点的距离为999。我们从第一条边(2->3 2)开始遍历,首先我们判断源点到顶点3的距离是小于源点到顶点2的距离加上这条边的边长2,松弛失败。接着我们开始判断第二条边(1->2 -3),此时我们发现源点到到2号顶点的距离大于了源点到1号顶点(源点 0)加上这条边的边长-3,松弛成功。根据以上方法进行类推我们最终可以获得源点到每个顶点的最短路径。
那么以上遍历需要进行多少轮呢?答案是:n-1轮(n为顶点的个数)。
最短路径肯定是一个不包含回路的简单路径。回路可分为正权回路(回路权值之和为正)和负权回路(回路权值之和为负),我们假设最短路径中存在正权回路,那么我们只需要去掉这个回路,一定可以获得更短的路径。如果存在负权回路那么我们每多走一次负权回路即可获得更短的路径。所以我们可以确定在一个有n个顶点的图中,任意两点之间的最短路径最多包含n-1条边。
private int[] u = new int[5];
private int[] v = new int[5];
private int[] w = new int[5];
private int[] dis = new int[5];
private void initArrs() {
for (int i = 1; i <= 4; i++) {
dis[i] = 999;
}
u[0] = 1;
v[0] = 2;
w[0] = 2;
u[1] = 0;
v[1] = 1;
w[1] = -3;
u[2] = 0;
v[2] = 4;
w[2] = 5;
u[3] = 3;
v[3] = 4;
w[3] = 2;
u[4] = 2;
v[4] = 3;
w[4] = 3;
}
@Test
public void testBellmanFord() {
initArrs();
for (int i = 0; i <= 4; i++) {
boolean check = true;
for (int j = 0; j <= 4; j++) {
if (dis[v[j]] > dis[u[j]] + w[j]) {
dis[v[j]] = dis[u[j]] + w[j];
check = false;//如果此循环没有一次进入该判断,则没有边可以进行松弛,即所有边都松弛成功,不需要再进行循环判断
}
}
if (check) {
break;
}
}
for (int i = 0; i <= 4; i++) {
if (dis[v[i]] > dis[u[i]] + w[i]) {
System.out.println("此图含有负权回路");
}
}
for (int i = 0; i <= 4; i++) {
System.out.println(dis[i]);
}
}