引入
随手笔记,做的不好见谅。
DijKstra算法个人理解
- 每次取出最短路径的顶点
- 由该点进行扩散,遍历该点的邻接点得到新点
- 若源点到该点+该点到新点<源点到新点,就更新源点到新点的值
- 添加进该新点进队列下次由它扩散,如此循环
代码
1.用邻接矩阵表示的图
import java.util.Scanner;
public class DijkstraMatrixShoterPath {
static int n;// 点数
static int e;// 边数
static int G[][];// 领接矩阵
static boolean visit[];// 是否访问过的节点
static int dis[];// 路径 dis[i] = j, 默认1到节点i最短路径j
static int path[];// 记录路线
// 寻找源点到节点最下的路径节点,并且没有访问过的
public static int findMinNode(){
int max = Integer.MAX_VALUE;
int node = -1;
for(int i = 1; i <= n; i++){
if(dis[i] < max && !visit[i]){
max = dis[i];
node = i;
}
}
return node;// 如果返回-1代表没找到
}
// dij
public static void dijstrax(int yuan){
// 初始化源点为0代表最小,第一个取出
dis[yuan] = 0;
path[yuan] = -1;// 源点记录区分
int u = 0;
while(true){
u = findMinNode();
// =-1代表都访问过并扩散了,可以退出了
if(u == -1){
break;
}
// 标记访问了当前节点
visit[u] = true;
// 以当前u节点,扩散它的领接点
for(int j = 1; j <= n; j++){
/*
当前j点没访问过,并且有路径。
*/
if(!visit[j] && G[u][j] < Integer.MAX_VALUE){
// 如果:源点到点u+u点到j点 < 源点到j点,就更新源点到j点的距离。
if(dis[u] + G[u][j] < dis[j]){
dis[j] = dis[u] + G[u][j];
path[j] = u;
}
}
}
}
}
// 打印路径
public static void printPath(int u){
// 如果是0代表到达起点
if(path[u] == -1){
System.out.print("路径:"+u+"->");
}else{
// 上一层
printPath(path[u]);
// 递归结束,打印路径
System.out.print(u+"->");
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
e = sc.nextInt();
// 初始化
G = new int[n + 1][n + 1];
dis = new int[n + 1];
path = new int[n + 1];
visit = new boolean[n + 1];
// 初始化正无穷
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
G[i][j] = Integer.MAX_VALUE;
}
}
// 路径初始化为正无穷
for(int i = 0; i < dis.length; i++){
dis[i] = Integer.MAX_VALUE;
}
// 输入边
int u, v, vl;
for(int i = 0; i < e; i++){
u = sc.nextInt();
v = sc.nextInt();
vl = sc.nextInt();
G[u][v] = vl; // 有向有权图
}
// 从1开始的路径
dijstrax(1);
// 得到长度
for(int i = 2; i <= n; i++){
System.out.print("源点1到点"+i+"的长度:"+dis[i]+",");
// 打印路径
printPath(i);
System.out.println();
}
sc.close();
}
}
2.输入数据
6 8
1 2 2
1 3 1
2 6 6
3 4 2
3 5 10
3 6 2
4 5 3
4 6 1
3.对应的图
4.输出数据
5.邻接表表示图
import java.util.ArrayList;
import java.util.Scanner;
public class AdlistDijkstraShoterPath {
static class Edge{
int u, v, val;
public Edge(int u, int v, int val){
this.u = u;
this.v = v;
this.val = val;
}
}
static int n;// 点数
static int e;// 边数
static ArrayList<Edge> edgelist;// 边的具体信息
static ArrayList<Integer> G[]; // 邻接表 G[i] 。G[I] = list:J,K,顶点i的size条边,在edge保存的序号J、K
static boolean visit[];// 是否访问过的节点
static int dis[];// 路径 dis[i] = j, 默认1到节点i最短路径j
static int path[];// 记录路线
// 寻找源点到节点最下的路径节点,并且没有访问过的
public static int findMinNode(){
int max = Integer.MAX_VALUE;
int node = -1;
for(int i = 1; i <= n; i++){
if(dis[i] < max && !visit[i]){
max = dis[i];
node = i;
}
}
return node;// 如果返回-1代表没找到
}
// dij
public static void dijstrax(int yuan){
// 初始化源点为0代表最小,第一个取出
dis[yuan] = 0;
path[yuan] = -1;// 源点记录区分
int u = 0;
while(true){
u = findMinNode();
// =-1代表都访问过并扩散了,可以退出了
if(u == -1){
break;
}
// 标记访问了当前节点
visit[u] = true;
// 以当前u节点,扩散它的领接点
for(int j = 0; j < G[u].size(); j++){
// 从边list中取出具体边信息
Edge ed = edgelist.get(G[u].get(j));
// v点没有访问过
if(!visit[ed.v]){
// 如果:源点到点u+u点到v点 < 源点到j点 ,就更新
if(dis[u] + ed.val < dis[ed.v]){
dis[ed.v] = dis[u] + ed.val;
path[ed.v] = u;
}
}
}
}
}
// 打印路径
public static void printPath(int u){
// 如果是0代表到达起点
if(path[u] == -1){
System.out.print("路径:"+u+"->");
}else{
// 上一层
printPath(path[u]);
// 递归结束,打印路径
System.out.print(u+"->");
}
}
// 带权有向图的添加
public static void insertEdge(int from, int to, int vl){
edgelist.add(new Edge(from, to, vl));
// 在edgelist中的下标
int size = edgelist.size();
G[from].add(size - 1);// 在edgelist的下标
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
e = sc.nextInt();
// 初始化
edgelist = new ArrayList<Edge>();
G = new ArrayList[n + 1];
dis = new int[n + 1];
path = new int[n + 1];
visit = new boolean[n + 1];
// 初始化G
for(int i = 0; i < G.length; i++){
G[i] = new ArrayList<>();
}
// 路径初始化为正无穷
for(int i = 0; i < dis.length; i++){
dis[i] = Integer.MAX_VALUE;
}
// 输入边
for(int i = 0; i < e; i++){
insertEdge(sc.nextInt(), sc.nextInt(), sc.nextInt());
}
// 从1开始的路径
dijstrax(1);
// 得到长度
for(int i = 1; i <= n; i++){
System.out.print("源点1到点"+i+"的长度:"+dis[i]+",");
// 打印路径
printPath(i);
System.out.println();
}
sc.close();
}
}