用Java实现Dijkstra输出指定起点到终点的最短路径
来源:互联网 发布:2015旅游数据 编辑:程序博客网 时间:2024/05/18 02:28
最近在公司参加了一个比赛,其中涉及的一个问题,可以简化成如是描述:一个二维矩阵,每个点都有权重,需要找出从指定起点到终点的最短路径。
马上就想到了Dijkstra算法,所以又重新温故了一遍,这里给出Java的实现。
而输出最短路径的时候,在网上也进行了查阅,没发现什么标准的方法,于是在下面的实现中,我给出了一种能够想到的比较精简的方式:利用prev[]数组进行递归输出。
package graph.dijsktra;import graph.model.Point;import java.util.*;/** * Created by MHX on 2017/9/13. */public class Dijkstra { private int[][] map; // 地图结构保存 private int[][] edges; // 邻接矩阵 private int[] prev; // 前驱节点标号 private boolean[] s; // S集合中存放到起点已经算出最短路径的点 private int[] dist; // dist[i]表示起点到第i个节点的最短路径 private int pointNum; // 点的个数 private Map<Integer, Point> indexPointMap; // 标号和点的对应关系 private Map<Point, Integer> pointIndexMap; // 点和标号的对应关系 private int v0; // 起点标号 private Point startPoint; // 起点 private Point endPoint; // 终点 private Map<Point, Point> pointPointMap; // 保存点和权重的映射关系 private List<Point> allPoints; // 保存所有点 private int maxX; // x坐标的最大值 private int maxY; // y坐标的最大值 public Dijkstra(int map[][], Point startPoint, Point endPoint) { this.maxX = map.length; this.maxY = map[0].length; this.pointNum = maxX * maxY; this.map = map; this.startPoint = startPoint; this.endPoint = endPoint; init(); dijkstra(); } /** * 打印指定起点到终点的最短路径 */ public void printShortestPath() { printDijkstra(pointIndexMap.get(endPoint)); } /** * 初始化dijkstra */ private void init() { // 初始化所有变量 edges = new int[pointNum][pointNum]; prev = new int[pointNum]; s = new boolean[pointNum]; dist = new int[pointNum]; indexPointMap = new HashMap<>(); pointIndexMap = new HashMap<>(); pointPointMap = new HashMap<>(); allPoints = new ArrayList<>(); // 将map二维数组中的所有点转换成自己的结构 int count = 0; for (int x = 0; x < maxX; ++x) { for (int y = 0; y < maxY; ++y) { indexPointMap.put(count, new Point(x, y)); pointIndexMap.put(new Point(x, y), count); count++; allPoints.add(new Point(x, y)); pointPointMap.put(new Point(x, y), new Point(x, y, map[x][y])); } } // 初始化邻接矩阵 for (int i = 0; i < pointNum; ++i) { for (int j = 0; j < pointNum; ++j) { if (i == j) { edges[i][j] = 0; } else { edges[i][j] = 9999; } } } // 根据map上的权重初始化edges,当然这种算法是没有单独加起点的权重的 for (Point point : allPoints) { for (Point aroundPoint : getAroundPoints(point)) { edges[pointIndexMap.get(point)][pointIndexMap.get(aroundPoint)] = aroundPoint.getValue(); } } v0 = pointIndexMap.get(startPoint); for (int i = 0; i < pointNum; ++i) { dist[i] = edges[v0][i]; if (dist[i] == 9999) { // 如果从0点(起点)到i点最短路径是9999,即不可达 // 则i节点的前驱节点不存在 prev[i] = -1; } else { // 初始化i节点的前驱节点为起点,因为这个时候有最短路径的都是与起点直接相连的点 prev[i] = v0; } } dist[v0] = 0; s[v0] = true; } /** * dijkstra核心算法 */ private void dijkstra() { for (int i = 1; i < pointNum; ++i) { // 此时有pointNum - 1个点在U集合中,需要循环pointNum - 1次 int minDist = 9999; int u = v0; for (int j = 1; j < pointNum; ++j) { // 在U集合中,找到到起点最短距离的点 if (!s[j] && dist[j] < minDist) { // 不在S集合,就是在U集合 u = j; minDist = dist[j]; } } s[u] = true; // 将这个点放入S集合 for (int j = 1; j < pointNum; ++j) { // 以当前刚从U集合放入S集合的点u为基础,循环其可以到达的点 if (!s[j] && edges[u][j] < 9999) { if (dist[u] + edges[u][j] < dist[j]) { dist[j] = dist[u] + edges[u][j]; prev[j] = u; } } } } } private void printDijkstra(int endPointIndex) { if (endPointIndex == v0) { System.out.print(indexPointMap.get(v0) + ","); return; } printDijkstra(prev[endPointIndex]); System.out.print(indexPointMap.get(endPointIndex) + ","); } private List<Point> getAroundPoints(Point point) { List<Point> aroundPoints = new ArrayList<>(); int x = point.getX(); int y = point.getY(); aroundPoints.add(pointPointMap.get(new Point(x - 1, y))); aroundPoints.add(pointPointMap.get(new Point(x, y + 1))); aroundPoints.add(pointPointMap.get(new Point(x + 1, y))); aroundPoints.add(pointPointMap.get(new Point(x, y - 1))); aroundPoints.removeAll(Collections.singleton(null)); // 剔除不在地图范围内的null点 return aroundPoints; } public static void main(String[] args) { int map[][] = { {1, 2, 2, 2, 2, 2, 2}, {1, 0, 2, 2, 0, 2, 2}, {1, 2, 0, 2, 0, 2, 2}, {1, 2, 2, 0, 2, 0, 2}, {1, 2, 2, 2, 2, 2, 2}, {1, 1, 1, 1, 1, 1, 1} }; // 每个点都代表权重,没有方向限制 Point startPoint = new Point(0, 3); // 起点 Point endPoint = new Point(5, 6); // 终点 Dijkstra dijkstra = new Dijkstra(map, startPoint, endPoint); dijkstra.printShortestPath(); }}
package graph.model;public class Point { private int x; private int y; private int value; public Point(int x, int y) { this.x = x; this.y = y; } public Point(int x, int y, int value) { this.x = x; this.y = y; this.value = value; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } @Override public String toString() { return "{" + "x=" + x + ", y=" + y + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Point point = (Point) o; if (x != point.x) return false; return y == point.y; } @Override public int hashCode() { int result = x; result = 31 * result + y; return result; }}
阅读全文
0 0
- 用Java实现Dijkstra输出指定起点到终点的最短路径
- 迷宫的最短路径(BFS,起点到终点)
- (阶段三 dijkstra温习1.3)HDU 1874 畅通工程续(用dijkstra求单源起点和单点终点的最短路径(起点和终点动态给出))
- 有向图中单个源点到终点的最短路径--Dijkstra算法与实现
- DijkStra最短路径的C++实现与输出路径
- (阶段三 dijkstra算法温习1.2)HDU 2066 一个人的旅行(使用dijkstra来解决多源起点和多源终点的最短路径问题)
- (阶段三 dijkstra算法温习 1.6)POJ 2387 Til the Cows Come Home(使用dijkstra算法求单源起点和单源终点的最短路径)
- hdu 2680 最短路径 多起点一终点问题
- 5X5迷宫,求起点和终点的最短路径以及最短路径个数(百分数)
- 最短路径:HDU2006-一个人的旅行(多个起点,多个终点)
- 单源点最短路径Dijkstra算法的JAVA实现
- 单源点最短路径Dijkstra算法的JAVA实现
- 最短路径Dijkstra算法的JAVA实现--转载
- 单源点最短路径Dijkstra的java实现
- Dijkstra最短路径算法的java实现
- Dijkstra算法的最短路径实现
- dijkstra最短路径算法的实现
- 最短路径 输出路径 Dijkstra算法
- Two Paths HDU 次短路问题
- 入门赛10
- 30读书笔记之多线程编程
- SpringBoot入门
- 最新版Sublime Text3 3143 注册码
- 用Java实现Dijkstra输出指定起点到终点的最短路径
- [Noip2016]天天爱跑步 LCA+树上差分
- Redis 列表(List)
- spring AOP
- [MYSQL-5]排序检索数据
- --致橡树--
- poj1410(计算几何)
- R8 STM32 SPI—读写串行 FLASH
- Android自定义view(圆形进度条)