每对顶点的最短路径 : Johnson 算法
2013-08-30 16:05
465 查看
import org.apache.commons.lang.builder.ToStringBuilder; /** * 稀疏图上的Johnson算法 结合 BellmanFord 和 Dijkstra 算法 * */ public class Johnson { static final int M = 10000; // unreachable /** * <pre> * @param edges : G(V,E) * @param dist : 计算的最短路径结果 * @param p : 记录前序节点 * @param s : 源点 * @return * </pre> */ static boolean bellmanFord(int[][] edges, int[] dist, int[] p, int s) { int n = edges.length; if (dist == null) { dist = new int ; } if (p == null) { p = new int ; } // init for (int i = 0; i < n; i++) { dist[i] = M; p[i] = -1; } dist[s] = 0; p[s] = -1; // 最短路径中最多含有n-1条边 for (int cnt = 1; cnt < n; cnt++) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (edges[i][j] < M && dist[j] > (dist[i] + edges[i][j])) { dist[j] = dist[i] + edges[i][j]; p[j] = i; } } } } // 判断是否存在负权环 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (edges[i][j] < M) { if (dist[j] > dist[i] + edges[i][j]) // 存在 return false; } } } return true; } /** * <pre> * @param edges : G(V,E) * @param dist : 计算的最短路径结果 * @param p : 记录前序节点 * @param s : 源点 * </pre> */ static void dijkstra(int[][] edges, int[] dist, int[] p, int s) { int n = edges.length; if (dist == null) { dist = new int ; } if (p == null) { p = new int ; } // init boolean[] visited = new boolean ; for (int i = 0; i < n; i++) { dist[i] = Integer.MAX_VALUE; p[i] = -1; } // 源点的值置为0 dist[s] = 0; p[s] = -1; // n个点,n次循环 int cnt = n; while (cnt > 0) { cnt--; int idx = -1; int min = Integer.MAX_VALUE; // 选取dist中值最小的一个点, 用最小堆更好 for (int i = 0; i < n; i++) { if (!visited[i] && min > dist[i]) { min = dist[i]; idx = i; } } // union visited[idx] = true; // 计算最短路径 for (int j = 0; j < n; j++) { if (dist[j] > (dist[idx] + edges[idx][j])) { dist[j] = dist[idx] + edges[idx][j]; p[j] = idx; } } } } /** * 根据索引,返回对应的节点名称 * * @param i * @return */ static char node(int i) { return (char) ('A' + i); } /** * 打印从u->v的最短路径 * * <pre> * @param p : 记录前序节点 * @param u : 起始节点 * @param v : 终止节点 * @param d : 最短路径值 * </pre> */ static void printPath(int[] p, int u, int v, int d) { if (d == M) { System.out.printf("%c -> %c (∞) : \n", node(u), node(v)); return; } else { System.out.printf("%c -> %c (%d) : ", node(u), node(v), d); StringBuilder sb = new StringBuilder(); sb.append(node(v)); while (p[v] != -1) { sb.insert(0, node(p[v]) + " - "); v = p[v]; } System.out.println(sb.toString()); } } /** * <pre> * @param _edges * 1.通过增加一个s节点,并增加s->V的路径(edge[s][v] = 0; edge[v][s] = M;),并建立有向图G' * 2.对于G', 用Bellman-Ford 算法判断是否存在负权环 * 3.如果存在,退出,不存在,计算最短路径(int[] h)和前序节点 * 4.Reweighting, W(u,v)' = W(u, v) + h(u) - h(v); * 5.通过Dijkstra算法,计算图G'以每个节点为源点的最短路径 * 6.对计算得到的最短路径值进行恢复dist[u][v] = d[v] - h[u] + h[v]; * </pre> */ static void johnson(int[][] _edges) { int _n = _edges.length; //增加源点s, 构建图G' int s = _n; int n = _n + 1; int[][] edges = new int ; int[][] dist = new int[_n][_n]; for (int i = 0; i < _n; i++) { for (int j = 0; j < _n; j++) { edges[i][j] = _edges[i][j]; dist[i][j] = M; } edges[i][_n] = M; } //判断是否存在负权环,并且计算h int[] h = new int ; boolean noNegativeCycle = bellmanFord(edges, h, null, s); if (!noNegativeCycle) { System.out.println("G(V,E) exist negative cycle!"); return; } //Reweighting for (int i = 0; i < _n; i++) { for (int j = 0; j < _n; j++) { if (i != j && _edges[i][j] < M) edges[i][j] = _edges[i][j] + h[i] - h[j]; } } for (int i = 0; i < _n; i++) { for (int j = 0; j < _n; j++) { _edges[i][j] = edges[i][j]; } } // 通过Dijkstra算法,计算每个顶点为源点的最短路径 for (int i = 0; i < _n; i++) { int[] d = new int[_n]; int[] p = new int[_n]; dijkstra(_edges, d, p, i); for (int j = 0; j < _n; j++) { //数据恢复,得到最短路径 dist[i][j] = d[j] - h[i] + h[j]; //print printPath(p, i, j, dist[i][j]); } System.out.println(); } } public static void main(String[] args) { // int[][] edges = { // { 0, 3, 8, M, -4 }, // { M, 0, M, 1, 7 }, // { M, 4, 0, M, M }, // { 2, M, -5, 0, M }, // { M, M, M, 6, 0 } // }; int[][] edges = { {0, M, M, M, M, M, 9}, {20, 0, 10, 30, M, M, M}, {M, M, 0, M, 5, M, 18}, {M, M, M, 0, M, M, M}, {M, M, M, 12, 0, M, 15}, {M, M, M, M, 8, 0, 10}, {M, M, 18, M, M, M, 0} }; johnson(edges); } }
相关文章推荐
- 最短路径算法——Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson,无一幸免
- 每对顶点间的最短路径算法时间复杂度改进C++实现
- 多路径路由算法选择(7)——最短路径算法Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson
- 最短路径算法----Dijkstra Bellman-Ford Floyd-Warshall Johnson
- FLOYD每对顶点间最短路径算法
- 所有顶点之间的最短路径算法:Floyd算法。
- 顶点间最短路径长度之探寻算法
- 弗洛伊德算法得到图中任意两个顶点之间的最短路径
- 顶点间最短路径长度之探寻算法
- 每对顶点间的最短路径基本算法 --- 算法导论笔记
- 设计一个算法,采用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G采用邻接表存储)
- 算法导论之每对顶点间的最短路径
- 弗洛伊德算法求每一对顶点之间的最短路径
- 所有结点对的最短路径问题之Johnson算法
- 最短路径算法——Dijkstra,Bellman-Ford,Floyd-Warshall,Johnson
- 经典算法之Floyd算法(求图中任意一对顶点间的最短路径)
- 每对顶点的最短路径 : 基本算法
- 每对顶点间的最短路径算法时间复杂度改进C++实现
- 【算法导论】每对顶点之间的最短路径算法
- 设计一个算法,採用BFS方式输出图G中从顶点u到v的最短路径(不带权的无向连通图G採用邻接表存储)