package com.interview.graph;
import java.util.HashMap;
import java.util.Map;
/**
* Date 11/05/2015
* @author Tushar Roy
*
* Write program for Bellman Ford algorithm to find single source shortest path in directed graph.
* Bellman ford works with negative edges as well unlike Dijksra's algorithm. If there is negative
* weight cycle it detects it.
*
* Time complexity - O(EV)
* Space complexity - O(V)
*
* References
* https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
* http://www.geeksforgeeks.org/dynamic-programming-set-23-bellman-ford-algorithm/
*/
public class BellmanFordShortestPath {
//some random big number is treated as infinity. I m not taking INTEGER_MAX as infinity because
//doing any addition on that causes integer overflow
private static int INFINITY = 10000000;
class NegativeWeightCycleException extends RuntimeException {
}
public Map<Vertex<Integer>, Integer> getShortestPath(Graph<Integer> graph,
Vertex<Integer> sourceVertex) {
Map<Vertex<Integer>, Integer> distance = new HashMap<>();
Map<Vertex<Integer>, Vertex<Integer>> parent = new HashMap<>();
//set distance of every vertex to be infinity initially
for(Vertex<Integer> v : graph.getAllVertex()) {
distance.put(v, INFINITY);
parent.put(v, null);
}
//set distance of source vertex to be 0
distance.put(sourceVertex, 0);
int V = graph.getAllVertex().size();
//relax edges repeatedly V - 1 times
for (int i = 0; i < V - 1 ; i++) {
for (Edge<Integer> edge : graph.getAllEdges()) {
Vertex<Integer> u = edge.getVertex1();
Vertex<Integer> v = edge.getVertex2();
//relax the edge
//if we get better distance to v via u then use this distance
//and set u as parent of v.
if (distance.get(u) + edge.getWeight() < distance.get(v)) {
distance.put(v, distance.get(u) + edge.getWeight());
parent.put(v, u);
}
}
}
//relax all edges again. If we still get lesser distance it means
//there is negative weight cycle in the graph. Throw exception in that
//case
for (Edge<Integer> edge : graph.getAllEdges()) {
Vertex<Integer> u = edge.getVertex1();
Vertex<Integer> v = edge.getVertex2();
if (distance.get(u) + edge.getWeight() < distance.get(v)) {
throw new NegativeWeightCycleException();
}
}
return distance;
}
public static void main(String args[]){
Graph<Integer> graph = new Graph<>(false);
graph.addEdge(0, 3, 8);
graph.addEdge(0, 1, 4);
graph.addEdge(0, 2, 5);
graph.addEdge(1, 2, -3);
graph.addEdge(2, 4, 4);
graph.addEdge(3, 4, 2);
graph.addEdge(4, 3, 1);
BellmanFordShortestPath shortestPath = new BellmanFordShortestPath();
Vertex<Integer> startVertex = graph.getAllVertex().iterator().next();
Map<Vertex<Integer>,Integer> distance = shortestPath.getShortestPath(graph, startVertex);
System.out.println(distance);
}
}