1. Dijstra算法求解的是图中一个顶点到其余顶点的最短路径
Dijstra算法思想:设有两个顶点集合S和T,集合S中存放的图中已经找到最短路径的顶点,集合T中存放图中剩余顶点,初始状态的时候,集合S中只包含源点v0,然后不断从集合T中选取到顶点v0路径长度最短的顶点v并入到集合S中去,集合S每并入一个新的顶点,都要修改顶点v0到集合T中顶点的最短路径长度值
总结起来我感觉主要有两步:
① 选取源点到其余顶点路径最短的那个顶点
② 每选取一个顶点都要更新从源点到其余顶点的路径,因为每加入一个顶点,有可能使源点到其余顶点通过这个顶点的作用路径变得更短,比如源点0到3的路径一开始为4但是并入1节点之后那么路径为3变短了所以需要更新到3顶点的最短路径
2. 我感觉Dijkstra算法与Prim最小生成树的算法很类似,在编程方面上的区别:Prim算法中的d[]数组记录的是其余顶点到当前顶点的最短路径,而Dijkstra算法记录的是源点到其余顶点的最短路径,这个区别导致在更新d[]数组的时候的值也是不一样的,我们可以类比这两个算法来进一步理解其中的思想
下面是具体的有向有权的的一个例子:
假如以顶点0作为源点那么首先选取与顶点0相接的顶点,在循环中判断顶点0到相接的顶点的距离是否比之前源点到达这些顶点的路径是更短,可以发现路径是变短了,因为之前是没有路径到达1,3,4顶点的所以需要更新d[]数组中对应的三个顶点,下一次选取源点到达其余顶点中路径最短的,可以发现0到1顶点路径是最短的,所以选择1顶点,重复上面的步骤即可,可以发现1与3顶点相接,那么判断一下1顶点到3顶点的路径是否比之前源点到3的路径更短发现是变短了那么更新,以此类推其余顶点也是一样的道理
测试数据如下:
6
8
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
3. 具体的代码如下:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int n = 0;
static int edges = 0;
static int graph[][];
static int visit[];
static int d[];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("输入顶点数: ");
n = sc.nextInt();
graph = new int[n][n];
visit = new int[n];
d = new int[n];
System.out.println("输入边数: ");
edges = sc.nextInt();
System.out.println("输入起始顶点, 结束顶点和顶点之间边的权重: ");
for(int i = 0; i < edges; i++){
int start = sc.nextInt();
int end = sc.nextInt();
int weight = sc.nextInt();
graph[start][end] = weight;
}
//输入需要求解的源点
int u = sc.nextInt();
int res[] = Dijkstra(u);
for(int i = 0; i < res.length; i++){
System.out.print(res[i] + " ");
}
sc.close();
}
private static int[] Dijkstra(int u) {
Arrays.fill(d, Integer.MAX_VALUE);
d[u] = 0;
for(int i = 0; i < n; i++){
u = -1;
int min = Integer.MAX_VALUE;
for(int j = 0; j < n; j++){
if(visit[j] == 0 && d[j] < min){
u = j;
min = d[j];
}
}
if(u == -1) return d;
visit[u] = 1;
for(int v = 0; v < n; v++){
if(visit[v] == 0 && graph[u][v] != 0 && d[v] > d[u] + graph[u][v]){
d[v] = d[u] + graph[u][v];
}
}
}
return d;
}
}