一. 最短路径
单源最短路径问题:给定一个图G = ( V , E ) ,求源结点s ∈ V 到图中每个结点v ∈ V的最短路径。
1.dijkstra算法
Dijkstra算法就适用于解决带权重的有向图上的单源最短路径问题,同时算法要求图中所有边的权重非负
针对一个带权有向图G,将所有结点分为两组S和Q,S是已经确定最短路径的结点集合,在初始时为空(初始时就可以将源节点s放入,毕竟源节点到自己的代价是0),Q 为其余未确定最短路径的结点集合,每次从Q中找出一个起点到该结点代价最小的结点u ,将u 从Q 中移出,并放入S 中,对u 的每一个相邻结点v 进行松弛操作。松弛即对每一个相邻结点v ,判断源节点s到结点u 的代价与u 到v 的代价之和是否比原来s 到v 的代价更小,若代价比原来小则要将s 到v 的代价更新为s 到u 与u 到v 的代价之和,否则维持原样。(即以以u为拓展点, 去调整更新相邻的未拓展点与源点之间的最短路径), 如此一直循环直至集合Q 为空,即所有节点都已经查找过一遍并确定了最短路径,至于一些起点到达不了的结点在算法循环后其代价仍为初始设定的值,不发生变化。Dijkstra算法每次都是选择V-S中最小的路径节点来进行更新,并加入S中,所以该算法使用的是贪心策略
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Dijkstra {
public static void main(String[] args) {
//图用list[]数组表示, list[i] = {......}, i为出点, 的边
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
//用邻接矩阵
int[][] matrix = new int[n][n];
int m = scanner.nextInt();//m条边
for (int i = 0; i < n; i++) {
Arrays.fill(matrix[i], 0x3f3f3f3f);
}
for (int i = 0; i < n; i++) {
matrix[i][i] = 0;
}
for (int i = 0; i < m; i++) {
int v = scanner.nextInt();
int j = scanner.nextInt();
matrix[v][j] = matrix[j][v] = scanner.nextInt();
}
int[] dp = getMinDistance(matrix);
System.out.println(Arrays.toString(dp));
}
/**
* 源点即起始点默认为0
* 图的节点是0 到 n - 1
*
* @param matrix
* @return
*/
public static int[] getMinDistance(int[][] matrix) {
int n = matrix.length;
int[] dp = new int[n];
boolean[] visited = new boolean[n];
//visited数组判断当前顶点是否拓展过了
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
//优先级队列加入的二元组,第一个元素是入点,
//第二点是边的大小,小根堆用来找离源点最近并且还没有拓展的点
visited[0] = true;
for (int j = 1; j < n; j++) {
dp[j] = matrix[0][j];
queue.add(new int[]{j, dp[j]});
}
i