Bellman-Ford算法和Dijkstra算法都是求解图的最短路径的算法。
两者区别在于:Dijkstra要求图中不存在边权值之和为负数的环路,否则算法无法收敛;Bellman-Ford算法可以检测出图中是否存在权值之和为负数的环路。
下文中用到的Graph类参见博文。
package algorithm;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import matrix.Graph;
public class ShortestPath {
int origin;
int[] preNodes;
double[] distances;
boolean hasNegativeLoop;
public ShortestPath(int o, double[] dis, int[] pre, boolean has) {
origin = o;
preNodes = pre;
distances = dis;
hasNegativeLoop = has;
}
// 返回 o 到 d 的最短路程
static double Dijkstra(Graph g, int origin, int destination) {
return Dijkstra(g, origin).distances[destination];
}
// 返回 o 到所有节点的最短路程
static ShortestPath Dijkstra(Graph g, int origin) {
int nodeNum = g.getNodeNum();
// 初始化前向节点
int pre[] = new int[nodeNum];
pre[origin] = origin;
// 初始化距离向量
double[] distances = new double[nodeNum];
for (int i = 0; i < nodeNum; ++i) {
distances[i] = Graph.INF;
}
distances[origin] = 0;
// 初始化候选顶点集,即为起始节点
Set<Integer> V = new HashSet<Integer>();
V.add(Integer.valueOf(origin));
while (!V.isEmpty()) {
// 选出 V 中距离起点最近的节点,从V中删除
Integer toRemove = null;
double minDisInV = Graph.INF;
for (Integer i : V) {
if (distances[i] <= minDisInV) {
minDisInV = distances[i];
toRemove = i;
}
}
V.remove(toRemove);
// 在与toRemove的出边相连的节点中,选择节点 j
Map<Integer, Object> outEdges = g.getOutEdges(toRemove);
if (outEdges != null) {
for (Integer j : outEdges.keySet()) {
// 如果节点 j 可以使得距离向量更小,把 j 加入 V
if (distances[j] > distances[toRemove] + (double) outEdges.get(j)) {
distances[j] = distances[toRemove] + (double) outEdges.get(j);
pre[j] = toRemove;
if (!V.contains(j)) {
V.add(j);
}
}
}
}
}
return new ShortestPath(origin, distances, pre, false);
}
// 返回 o 到所有节点的最短路程
static ShortestPath BellmanFord(Graph g, int origin) {
int nodeNum = g.getNodeNum();
boolean hasNLoop = false;
// 初始化前向节点
int pre[] = new int[nodeNum];
pre[origin] = origin;
// 初始化距离向量
double[] distances = new double[nodeNum];
for (int i = 0; i < nodeNum; ++i) {
distances[i] = Graph.INF;
}
distances[origin] = 0;
int iteration = nodeNum;
while (iteration-- > 0) {
boolean update = false;
// 遍历所有的边
for (int i = 0; i < nodeNum; ++i) {
Map<Integer, Object> outEdges = g.getOutEdges(i);
if (outEdges != null) {
for (Integer j : outEdges.keySet()) {
// 如果节点 j 可以使得距离向量更小,把 j 加入 V
if (distances[j] > distances[i] + (double) outEdges.get(j)) {
update = true;
if (iteration == 0) {
hasNLoop = true;
break;
}
distances[j] = distances[i] + (double) outEdges.get(j);
pre[j] = i;
}
}
}
}
// 如果这次遍历没有任何更新,那么下一次也不会更新,提前退出循环
if (!update) {
break;
}
}
return new ShortestPath(origin, distances, pre, hasNLoop);
}
public void analyse() {
System.out.println("Negative loops exist: " + hasNegativeLoop);
for (int i = 0; i < distances.length; ++i) {
String c = distances[i] < Graph.INF ? String.valueOf(distances[i]) : "inf";
System.out.println("Distance from " + origin + " to " + i + ": " + c);
if (distances[i] < Graph.INF) {
int j = i;
while (j != origin) {
System.out.print(j + " <= ");
j = preNodes[j];
}
System.out.println(j);
}
}
}
来看小例子:
public static void main(String[] args) {
Graph g = new Graph(6,false);
double[][] triples = {
{1,2,2},
{2,1,-3},
{1,3,1},
{2,3,1},
{3,2,1},
{2,4,1},
{3,4,3},
{2,5,0},
{4,5,0}
};
g.addEdges(triples);
g.show();
ShortestPath sp = ShortestPath.BellmanFord(g, 1);
//ShortestPath sp = ShortestPath.Dijkstra(g, 1);
System.out.println();
sp.analyse();
}
}
图中存在负环是显然的,因为有 {1,2,2} 和 {2,1,-3}。
运行结果:
0.0 inf inf inf inf inf
inf 0.0 2.0 1.0 inf inf
inf -3.0 0.0 1.0 1.0 0.0
inf inf 1.0 0.0 3.0 inf
inf inf inf inf 0.0 0.0
inf inf inf inf inf 0.0
If negative loops exist: true
Distance from 1 to 0: inf
Distance from 1 to 1: -6.0
1
Distance from 1 to 2: -3.0
2 <= 1
Distance from 1 to 3: -4.0
3 <= 1
Distance from 1 to 4: -2.0
4 <= 2 <= 1
Distance from 1 to 5: -3.0
5 <= 2 <= 1
可以看出,只要一直循环下去,所有距离都会趋于负无穷。比如循环次数再翻一倍时:
If negative loops exist: true
Distance from 1 to 0: inf
Distance from 1 to 1: -12.0
1
Distance from 1 to 2: -9.0
2 <= 1
Distance from 1 to 3: -10.0
3 <= 1
Distance from 1 to 4: -8.0
4 <= 2 <= 1
Distance from 1 to 5: -9.0
5 <= 2 <= 1
事实上,只要重复 1=>2=>1=>2=>… 就会使总路程数不断减少。
来一个规模大一点的例子,节点数1000,边数100000:
int N = 1000;
Random rand = new Random();
Graph g = new Graph(N,false);
for(int i = 1; i<100000; ++i) {
g.addEdge(rand.nextInt(N),rand.nextInt(N),rand.nextDouble());
}
//g.show();
long begintime = System.nanoTime();
ShortestPath sp = ShortestPath.BellmanFord(g, 1);
//ShortestPath sp = ShortestPath.Dijkstra(g, 1);
long endtime = System.nanoTime();
System.out.println();
sp.analyse();
long costTime = (endtime - begintime)/1000000;
System.out.println("Time used: "+costTime);
结果:
Negative loops exist: false
Distance from 1 to 0: 0.1178139809154638
0 <= 212 <= 690 <= 213 <= 856 <= 89 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 1: 0.0
1
Distance from 1 to 2: 0.08065859993706903
2 <= 649 <= 669 <= 648 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 3: 0.08116689820549627
3 <= 648 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 4: 0.07111204888545863
4 <= 936 <= 563 <= 183 <= 449 <= 1
Distance from 1 to 5: 0.08827929338718277
5 <= 672 <= 527 <= 1
Distance from 1 to 6: 0.08270874263714678
6 <= 646 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 7: 0.06916873694425418
7 <= 484 <= 765 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 8: 0.10939175185848171
8 <= 364 <= 308 <= 199 <= 139 <= 670 <= 192 <= 527 <= 1
Distance from 1 to 9: 0.0783899669706094
9 <= 440 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 10: 0.10397438373195189
10 <= 511 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 11: 0.11045791932386517
11 <= 597 <= 551 <= 440 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 12: 0.0834832517606845
12 <= 594 <= 646 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 13: 0.06632569195821614
13 <= 236 <= 494 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 14: 0.10684510424753724
14 <= 63 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 15: 0.08256547299665895
15 <= 420 <= 697 <= 645 <= 262 <= 124 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 16: 0.1096329758525515
16 <= 706 <= 768 <= 487 <= 695 <= 211 <= 99 <= 527 <= 1
Distance from 1 to 17: 0.07537571922046005
17 <= 911 <= 262 <= 124 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 18: 0.09925216239038415
18 <= 827 <= 32 <= 856 <= 89 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 19: 0.09683672016487854
19 <= 229 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 20: 0.07427699189492398
20 <= 357 <= 484 <= 765 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 21: 0.07783416800299692
21 <= 793 <= 733 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 22: 0.07238442992454519
22 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 23: 0.10495390887155953
23 <= 843 <= 182 <= 937 <= 504 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 24: 0.05879953933073656
24 <= 937 <= 504 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 25: 0.0641243897072653
25 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 26: 0.1085529028004284
26 <= 238 <= 352 <= 962 <= 351 <= 38 <= 948 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 27: 0.0899738066585356
27 <= 157 <= 594 <= 646 <= 973 <= 693 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 28: 0.0999880744962669
28 <= 409 <= 169 <= 869 <= 593 <= 494 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 29: 0.06865435688074473
29 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 30: 0.07711943673683253
30 <= 296 <= 677 <= 831 <= 113 <= 935 <= 211 <= 99 <= 527 <= 1
Distance from 1 to 31: 0.07994800205405383
31 <= 807 <= 837 <= 311 <= 527 <= 1
Distance from 1 to 32: 0.061525207871197085
32 <= 856 <= 89 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 33: 0.08460781199640222
33 <= 688 <= 631 <= 657 <= 148 <= 727 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 34: 0.02890762140659775
34 <= 527 <= 1
Distance from 1 to 35: 0.1046550946041277
35 <= 977 <= 702 <= 53 <= 570 <= 837 <= 311 <= 527 <= 1
Distance from 1 to 36: 0.13133006328285102
36 <= 975 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 37: 0.056090552427294105
37 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 38: 0.061921084222054334
38 <= 948 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 39: 0.06717751235710434
39 <= 464 <= 124 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 40: 0.11382708513290962
40 <= 947 <= 440 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 41: 0.1295413711710246
41 <= 817 <= 124 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 42: 0.09663809457384731
42 <= 260 <= 115 <= 105 <= 925 <= 222 <= 100 <= 99 <= 527 <= 1
Distance from 1 to 43: 0.10171582504910237
43 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 44: 0.09501074073877458
44 <= 253 <= 89 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 45: 0.07479613246873362
45 <= 660 <= 206 <= 451 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 46: 0.06866370335208771
46 <= 29 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 47: 0.0807521297774576
47 <= 986 <= 231 <= 648 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 48: 0.05191128475116591
48 <= 199 <= 139 <= 670 <= 192 <= 527 <= 1
Distance from 1 to 49: 0.09988621914030427
49 <= 965 <= 907 <= 629 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 50: 0.08745823185614554
50 <= 60 <= 789 <= 651 <= 211 <= 99 <= 527 <= 1
Distance from 1 to 51: 0.11407297028631058
51 <= 928 <= 450 <= 182 <= 937 <= 504 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 52: 0.061169794677373046
52 <= 979 <= 416 <= 1
Distance from 1 to 53: 0.06555191782814462
53 <= 570 <= 837 <= 311 <= 527 <= 1
Distance from 1 to 54: 0.08523879526475608
54 <= 148 <= 727 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 55: 0.06897354633883912
55 <= 37 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 56: 0.08177961186258864
56 <= 100 <= 99 <= 527 <= 1
Distance from 1 to 57: 0.07589364300347312
57 <= 297 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 58: 0.09853633153153618
58 <= 730 <= 742 <= 510 <= 952 <= 39 <= 464 <= 124 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
Distance from 1 to 59: 0.09660177072593423
59 <= 950 <= 678 <= 416 <= 1
Distance from 1 to 60: 0.0783128445194986
60 <= 789 <= 651 <= 211 <= 99 <= 527 <= 1
Distance from 1 to 61: 0.08470638910659423
61 <= 468 <= 446 <= 236 <= 494 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 62: 0.10259684812334335
62 <= 370 <= 572 <= 590 <= 670 <= 192 <= 527 <= 1
Distance from 1 to 63: 0.06518156347888071
63 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 64: 0.07437738917311543
64 <= 629 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 65: 0.09820819272133674
65 <= 325 <= 577 <= 97 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 66: 0.10305719662831214
66 <= 59 <= 950 <= 678 <= 416 <= 1
Distance from 1 to 67: 0.07217736502084782
67 <= 968 <= 52 <= 979 <= 416 <= 1
Distance from 1 to 68: 0.05390701339738624
68 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 69: 0.14212211421884402
69 <= 449 <= 1
Distance from 1 to 70: 0.08397070309308208
70 <= 763 <= 63 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 71: 0.07922755905933787
71 <= 394 <= 449 <= 1
Distance from 1 to 72: 0.10215072660794733
72 <= 769 <= 231 <= 648 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 73: 0.10804506653056112
73 <= 66 <= 59 <= 950 <= 678 <= 416 <= 1
Distance from 1 to 74: 0.040248223002147476
74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 75: 0.0728479934920101
75 <= 569 <= 580 <= 900 <= 839 <= 781 <= 527 <= 1
此处略去1800行……
Distance from 1 to 975: 0.04934329085366129
975 <= 173 <= 192 <= 527 <= 1
Distance from 1 to 976: 0.0959283679740528
976 <= 481 <= 605 <= 733 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 977: 0.08984512197925976
977 <= 702 <= 53 <= 570 <= 837 <= 311 <= 527 <= 1
Distance from 1 to 978: 0.08561735049702224
978 <= 467 <= 161 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 979: 0.04707597617645698
979 <= 416 <= 1
Distance from 1 to 980: 0.08035283111667768
980 <= 934 <= 104 <= 416 <= 1
Distance from 1 to 981: 0.07975587841442533
981 <= 791 <= 88 <= 987 <= 190 <= 133 <= 68 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 982: 0.07812479259437066
982 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 983: 0.0868834962372359
983 <= 564 <= 342 <= 494 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 984: 0.11375195012192885
984 <= 367 <= 631 <= 657 <= 148 <= 727 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 985: 0.08272028915519736
985 <= 987 <= 190 <= 133 <= 68 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 986: 0.07275958862760723
986 <= 231 <= 648 <= 633 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 987: 0.06923073127552015
987 <= 190 <= 133 <= 68 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 988: 0.0770690343585757
988 <= 694 <= 48 <= 199 <= 139 <= 670 <= 192 <= 527 <= 1
Distance from 1 to 989: 0.09581754395677411
989 <= 865 <= 340 <= 148 <= 727 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 990: 0.06217346784414157
990 <= 615 <= 835 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 991: 0.09813339143101862
991 <= 606 <= 547 <= 738 <= 556 <= 240 <= 642 <= 38 <= 948 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 992: 0.10363541184241176
992 <= 976 <= 481 <= 605 <= 733 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 993: 0.11613209524413759
993 <= 618 <= 350 <= 267 <= 450 <= 182 <= 937 <= 504 <= 729 <= 781 <= 527 <= 1
Distance from 1 to 994: 0.10590106175797098
994 <= 961 <= 608 <= 990 <= 615 <= 835 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 995: 0.08245117830714233
995 <= 793 <= 733 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 996: 0.08243467703191232
996 <= 490 <= 218 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 997: 0.07808150350591492
997 <= 37 <= 228 <= 422 <= 103 <= 781 <= 527 <= 1
Distance from 1 to 998: 0.10833415588585826
998 <= 965 <= 907 <= 629 <= 755 <= 595 <= 74 <= 123 <= 34 <= 527 <= 1
Distance from 1 to 999: 0.08559650731829094
999 <= 603 <= 897 <= 74 <= 123 <= 34 <= 527 <= 1
Time used: 487
刺激吧!只用了487ms!