Single-Source Shortest Paths
1. Dijkstra's Algorithm
Dijkstra's Algorithm is widely used to determine the single-source shortest path in a weighted graph whose weights are all non-negative. Here is my solution to a problem from SJTU ACM Online Judge, in which I used this algorithm to determine the shortest path between two specific vertices:
1 import java.util.*; 2 3 class AdjList { 4 private class Vert { 5 public Edge next; 6 } 7 private class Edge { 8 public int end, weight; 9 public Edge next; 10 11 public Edge(int end,int weight,Edge next) { 12 this.end = end; 13 this.weight = weight; 14 this.next = next; 15 } 16 } 17 private class HeapItem { 18 public int idx, dist; 19 20 public HeapItem(int idx,int dist) { 21 this.idx = idx; 22 this.dist = dist; 23 } 24 public int index() { 25 return idx; 26 } 27 } 28 29 private final int INF = 1000001; 30 private int num; 31 private Vert [] vert; 32 33 public AdjList(int num) { 34 this.num = num; 35 vert = new Vert[num]; 36 for (int i=0;i<num;i++) { 37 vert[i] = new Vert(); 38 } 39 } 40 public void insert(int i,int j,int w) { 41 vert[i].next = new Edge(j,w,vert[i].next); 42 } 43 private void printPath(int [] prev,int pos) { 44 if (prev[pos]<0) { 45 System.out.print(pos+1); 46 } else { 47 printPath(prev,prev[pos]); 48 System.out.print(" "+(pos+1)); 49 } 50 } 51 public void shortPath(int p,int r) { 52 PriorityQueue<HeapItem> q = new PriorityQueue<HeapItem>(10000, 53 new Comparator<HeapItem>() { 54 public int compare(HeapItem a,HeapItem b) { 55 if (a.dist<b.dist) { 56 return -1; 57 } else if (a.dist>b.dist) { 58 return 1; 59 } else { 60 return 0; 61 } 62 } 63 } 64 ); 65 boolean [] vis = new boolean[num]; 66 int [] dist = new int [num]; 67 int [] cnt = new int [num]; 68 int [] prev = new int [num]; 69 // initialize single source: 70 for (int i=0;i<num;i++) { 71 dist[i] = cnt[i] = INF; 72 } 73 dist[p] = 0; 74 cnt[p] = 0; 75 prev[p] = -1; 76 q.add(new HeapItem(p,0)); 77 int pos = -1; 78 while (!q.isEmpty()) { 79 do { 80 pos = q.poll().index(); 81 } while (vis[pos]); 82 vis[pos] = true; 83 if (pos==r) { 84 break; 85 } 86 Edge itr = vert[pos].next; 87 while (itr!=null) { 88 // do relaxation for each vertex adjacent to vert[pos] 89 if (!vis[itr.end] && dist[itr.end]>dist[pos]+itr.weight) { 90 dist[itr.end] = dist[pos]+itr.weight; 91 cnt[itr.end] = cnt[pos]+1; 92 prev[itr.end] = pos; 93 q.add(new HeapItem(itr.end,dist[itr.end])); 94 } else if (!vis[itr.end]&&dist[itr.end]==dist[pos]+itr.weight&&cnt[itr.end]>cnt[pos]+1) { 95 cnt[itr.end] = cnt[pos]+1; 96 prev[itr.end] = pos; 97 } 98 itr = itr.next; 99 } 100 } 101 System.out.println(dist[r]); 102 printPath(prev,r); 103 System.out.println(); 104 } 105 } 106 107 public class Main { 108 public static void main(String[] args) { 109 Scanner in = new Scanner(System.in); 110 int v = in.nextInt(); 111 int e = in.nextInt(); 112 int p = in.nextInt()-1; 113 int r = in.nextInt()-1; 114 AdjList g = new AdjList(v); 115 for (int i=0;i<e;i++) { 116 int j = in.nextInt()-1; 117 int k = in.nextInt()-1; 118 int w = in.nextInt(); 119 g.insert(j,k,w); 120 } 121 in.close(); 122 g.shortPath(p,r); 123 } 124 }
2. Bellman-Ford Algorithm
This is an algorithm that can determine the single-source shortest paths in a weighted graph even if the graph has negative weights. I used it to solve a problem from SJTU ACM Online Judge:
1 import java.util.*; 2 3 class AdjList { 4 private static class Vert { 5 public Vert next; 6 public int weight,end; 7 } 8 9 private final int INF = 10000000; 10 private int num; 11 private Vert[] vert; 12 13 public AdjList(int num) { 14 this.num = num; 15 vert = new Vert[num]; 16 for (int i=0;i<num;i++) { 17 vert[i] = new Vert(); 18 } 19 } 20 public void insEdge(int p,int r,int w) { 21 Vert v = new Vert(); 22 v.next = vert[p].next; 23 v.weight = w; 24 v.end = r; 25 vert[p].next = v; 26 } 27 public int shortPath(int src,int dest) { 28 // Bellman-Ford Algorithm: 29 // Precondition: no negative-weight cycles exist 30 // Postcondition: return the shortest distance 31 // between vert[src] and vert[dest] 32 int[] dist = new int[num]; 33 for (int i=0;i<num;i++) { 34 dist[i] = INF; 35 } 36 dist[src] = 0; 37 for (int i=1;i<num;i++) { 38 // for each vertices do relaxation (num-1) times 39 for (int j=0;j<num;j++) { 40 Vert itr = vert[j].next; 41 while (itr!=null) { 42 relax(j,itr,dist); 43 itr = itr.next; 44 } 45 } 46 } 47 return dist[dest]; 48 } 49 private boolean relax(int i,Vert v,int[] dist) { 50 if (dist[i]+v.weight<dist[v.end]) { 51 dist[v.end] = dist[i]+v.weight; 52 return true; 53 } else { 54 return false; 55 } 56 } 57 } 58 59 public class Main { 60 public static Scanner in; 61 62 public static void main(String[] args) { 63 in = new Scanner(System.in); 64 AdjList g = new AdjList(in.nextInt()); 65 int m = in.nextInt(); 66 int s = in.nextInt()-1; 67 int d = in.nextInt()-1; 68 for (int i=0;i<m;i++) { 69 int p = in.nextInt()-1; 70 int r = in.nextInt()-1; 71 int w = in.nextInt(); 72 g.insEdge(p,r,w); 73 } 74 in.close(); 75 System.out.println(g.shortPath(s,d)); 76 } 77 }
3. SPFA Algorithm
For the problem above, we can have a more efficient solution if we draw on another algorithm called SPFA (Shortest Path Faster Algorithm):
1 import java.util.*; 2 3 class AdjList { 4 private class Vert { 5 public Edge next; 6 } 7 private class Edge { 8 public int end, weight; 9 public Edge next; 10 11 public Edge(int end,int weight,Edge next) { 12 this.end = end; 13 this.weight = weight; 14 this.next = next; 15 } 16 } 17 18 public final int INF = 1000001; 19 private int num; 20 private Vert [] vert; 21 22 public AdjList(int num) { 23 this.num = num; 24 vert = new Vert[num]; 25 for (int i=0;i<num;i++) { 26 vert[i] = new Vert(); 27 } 28 } 29 public void insEdge(int i,int j,int w) { 30 vert[i].next = new Edge(j,w,vert[i].next); 31 } 32 public int shortPath(int p,int r) { 33 Queue<Integer> q = new LinkedList<Integer>(); 34 int [] dist = new int[num]; 35 for (int i=0;i<num;i++) { 36 dist[i] = INF; 37 } 38 dist[p] = 0; 39 q.add(new Integer(p)); 40 while (!q.isEmpty()) { 41 int pos = q.poll().intValue(); 42 Edge itr = vert[pos].next; 43 while (itr!=null) { 44 // do relaxation for each vertex adjacent to vert[pos] 45 if (dist[itr.end]>dist[pos]+itr.weight) { 46 dist[itr.end] = dist[pos]+itr.weight; 47 q.add(new Integer(itr.end)); 48 } 49 itr = itr.next; 50 } 51 } 52 return dist[r]; 53 } 54 private void printPath(int [] prev,int pos) { 55 if (prev[pos]<0) { 56 System.out.print(pos+1); 57 } else { 58 printPath(prev,prev[pos]); 59 System.out.print(" "+(pos+1)); 60 } 61 } 62 } 63 64 public class Main { 65 public static void main(String[] args) { 66 Scanner in = new Scanner(System.in); 67 int v = in.nextInt(); 68 int e = in.nextInt(); 69 int p = in.nextInt()-1; 70 int r = in.nextInt()-1; 71 AdjList g = new AdjList(v); 72 for (int i=0;i<e;i++) { 73 int j = in.nextInt()-1; 74 int k = in.nextInt()-1; 75 int w = in.nextInt(); 76 g.insEdge(j,k,w); 77 } 78 in.close(); 79 System.out.println(g.shortPath(p, r)); 80 } 81 }
References:
1. Cormen, T. H. et al. Introduction to Algorithms [M] . 北京:机械工业出版社, 2006-09