一、最短路径分析
比如我们现在要对一个地图计算最短路径,首先我们要解决这个问题就要找准一个数据结构,很显然地图肯定是用图结构来表示最好了。
具体:我们可以把每个路口看成一个点,路口之间的路看作一条边。路的长度就是边的权重,即可得到以下这个图形:
这里我们就将地图转换成了我们熟悉的数据结构图,那么假设我要从1点作为起点,则就变成求1点到其他点的最短路径。
一般可以有三种解决思路:动态规划、DFS(深度优先遍历算法)、贪心算法,这里介绍用动态规划的思想来解决。
算法选择:经典算法之迪杰斯特拉(Dijkstra)算法,即单源最短路径算法,它是所有最短路径算法的基础,我们的地图软件最终使用的算法也是以他为基础进行的优化。所以弄懂它变得尤为重要。
二、迪杰斯特拉(Dijkstra)算法思路
核心思想分析:排序 + 贪心,
1.我们开一个dis数组,用来表示起始点到每个顶点的距离,最开始时我们赋值为无穷大。
2.加变量loc,初始赋值为起始点。
贪心的策略:在dis数组里面找离初始点最近的那个点
3.通过loc更新dis数组,因为加入一个点后我们就可以更新路径
4.在dis数组里面找离初始点最近的那个点,排除已经选择过的点,将之赋值给loc。
5.重复执行 3 4操作,直到所有点加完。
其中核心操作是第三步:我们应该如何来更新dis数组呢?
三、参考代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Djstl {
/**
6
8
1
1 3 10
1 5 50
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
*/
public static void main(String[] args) {
int n, m, x; // n表示点数,m表示边数,x表示我们起点
Map<Integer,String> routes = new HashMap<>();
Scanner cin = new Scanner(System.in);
n = cin.nextInt();
m = cin.nextInt();
x = cin.nextInt();
int value[][] = new int[n + 1][n + 1]; // 表示点到点的邻接矩阵
int dis[] = new int[n + 1]; // 存最短路径的
for (int i = 1; i <= n; i++) {
dis[i] = Integer.MAX_VALUE;
for (int j = 1; j <= n; j++) {
// 初始化我们的地图
value[i][j] = -1; // 表示没有路的
if (i == j) {
value[i][j] = 0;
}
}
routes.put(i,"");
}
for (int i = 0; i < m; i++) { // 表示要输入m个边
int xx = cin.nextInt();
int yy = cin.nextInt();
int v = cin.nextInt(); // xx yy v表示从xx到yy有一条路 长度是v
value[xx][yy] = v;
// dis其实在第一个点时候可以在这里计算
if (xx == x) {
dis[yy] = v;
}
}
seach(x, dis, value, n,routes);
}
public static void seach(int x, int dis[], int value[][], int n,Map<Integer,String> routes) {
boolean mark[] = new boolean[n + 1];
mark[x] = true;
dis[x] = 0;
int count = 1;
routes.put(x,String.valueOf(x));
while (count <= n) { //O(n^2)
int loc = 0; // 表示新加的点
int min = Integer.MAX_VALUE;
for (int i = 1; i <= n; i++) { // 求dis里面的最小值 优先队列,堆 logn
if (!mark[i] && dis[i] < min) {
min = dis[i];
loc = i;
}
}
if (loc == 0) {
break; // 表示没有可以加的点了
}
// 初始化第一个新加进来的节点
if (routes.get(loc) == ""){
routes.put(loc,"1->" + loc);
}
mark[loc] = true;
//只需要关注 我们加进来的点 能有哪些路径就可以了,不用扫描所有的dis 最好的情况应该可以达到o(nlogn),最坏的情况才是O(n^2)
for (int i = 1; i <= n; i++) {
if (value[loc][i] != -1 && (dis[loc] + value[loc][i] < dis[i])) {
dis[i] = dis[loc] + value[loc][i];
routes.put(i,routes.get(loc) + "->" + i);
}
}
count++;
}
for (int i = 1; i <= n; i++) {
System.out.println(x + "到 " + i + "的最短路径为 :" + dis[i]);
}
for (int i = 1; i <= n; i++) {
System.out.println(x + "到 " + i + "的最短路径为 :" + routes.get(i));
}
}
}
dis[i]);
}
for (int i = 1; i <= n; i++) {
System.out.println(x + "到 " + i + “的最短路径为 :” + routes.get(i));
}
}
}