最短路径问题
最短路径
在上篇007的问题中,若想求得可行路径中,路径最短的一条路是什么呢?
无权图的单源最短路径
复习:无权图。权:在图的边和弧相关的数,权可以表示从一个顶点到另一个顶点的耗费/距离等;
算法思想:
通过bfs算法,当每一层的结点都遍历,判断当前层的结点的属性;判断这层结点是否符合你的end要求(例如 007是否跳至岸边);因为bfs算法是每层的扫描,当前层入符合end要求,必然是最短路径;
故我们需要在bfs循环中,去保存当前的层的distance(距离)或者path(路径),可以采取数组/map等数据结构,同时也可以自己创建类;
前篇007:https://editor.csdn.net/md/?articleId=104146261
007问题深化:求007的最短路径需要跳多少次,或者求007的路径
下列为解决代码,若需要路径,遍历下述的path的HashMap 即可拿到;
注意:path中存的为每个结点的最短路径中的父类结点对象;拿到具体路径,直接遍历达到终止时即可;
public int shortestWay(Node node) {
HashMap<String, Integer> dist = new HashMap<>();
HashMap<Node, Node> path = new HashMap<>();
Queue<Node> queue = new Queue<>();
queue.add(node);
dist.put(node.name, 0);
path.put(node, null);
Node endNode = null;
while (queue.isEmpty()) {
Node node1 = queue.peek();
for (Node nearNode : node1.nearNode()) {
if (!dist.containsKey(nearNode.name)) {
dist.put(nearNode.name, dist.get(node1.name) + 1);
path.put(nearNode, node1);
queue.add(nearNode);
if ((Math.abs(nearNode.x) - xEdge) < 1 || (Math.abs(nearNode.y) - yEdge) < 1) {
endNode = nearNode;
break;
}
}
}
}
if (endNode == null) throw new RuntimeException("can't jump to edge");
return dist.get(endNode.name);
}
###有权图的单源最短路径算法
Dijkstra算法
核心思想:在无权最短路径算法的基础,增加当前收录源点s 和 到达该目的地的v的 的最短路径的权值/路径,当权值/路径大于了当前权值,说明非权重最小的情况,不断的让该权重递减,退出循环时,即是最小权值;在此过程中,不断收录最短路径的顶点v;
换言之:A->…->B->…->C是A到C的一条最短路径,那么这条路径中经过B点,在这条路径中A到B的路径也是A到B的最短路径,即:一条最短路径中包含路过的所有节点的最短路径
令s = {源点s + 已经确定了最短路径的顶点vi}
对任一路径v,定义dist[v]为s到v的最短路径长度,但该路径仅经历s中收录的顶点。
若路径按递增顺序生成,则:
- 真正的最短路径必须只经过s中收录过的顶点
- 每次未收录的顶点中选一个dist最小的收录
需要基于邻接矩阵 / 邻接表 进行实现:
复习:https://blog.csdn.net/qq_32193775/article/details/104133695
//伪代码如下
public void dijkstra(int v){
while(true){
}
}
代码如下:
public int[] dijkstra(int v) {
if (v < 0 || v >= numOfVexs)
throw new ArrayIndexOutOfBoundsException();
boolean[] st = new boolean[numOfVexs];// 默认初始为false
int[] distance = new int[numOfVexs];// 存放源点到其他点的矩离
for (int i = 0; i < numOfVexs; i++)
for (int j = i + 1; j < numOfVexs; j++) {
if (edges[i][j] == 0) {
edges[i][j] = Integer.MAX_VALUE;
edges[j][i] = Integer.MAX_VALUE;
}
}
for (int i = 0; i < numOfVexs; i++) {
distance[i] = edges[v][i];
}
st[v] = true;
// 处理从源点到其余顶点的最短路径
for (int i = 0; i < numOfVexs; ++i) {
int min = Integer.MAX_VALUE;
int index=-1;
// 比较从源点到其余顶点的路径长度
for (int j = 0; j < numOfVexs; ++j) {
// 从源点到j顶点的最短路径还没有找到
if (st[j]==false) {
// 从源点到j顶点的路径长度最小
if (distance[j] < min) {
index = j;
min = distance[j];
}
}
}
//找到源点到索引为index顶点的最短路径长度
if(index!=-1)
st[index] = true;
// 更新当前最短路径及距离
for (int w = 0; w < numOfVexs; w++)
if (st[w] == false) {
if (edges[index][w] != Integer.MAX_VALUE
&& (min + edges[index][w] < distance[w]))
distance[w] = min + edges[index][w];
}
}
return distance;
}