Loading

Dijkstra求最短路

一、问题解析

原题链接:https://www.acwing.com/problem/content/851/

image-20220402234531172

最短路问题是图论中的一个基本问题——给定一张有权图,如何求某两点之间的最短路径?

Dijkstra算法:

Dijkstra算法通常是求解单源最短路中最快的算法,但它无法处理存在负权边(权重为负数)的情况。Dijkstra本质上是一种贪心算法,通过不断调整每个点的“当前距离”最终得到最优结果,采用步步逼近的手段。

Dijkstra 算法是一种类似于贪心的算法,步骤如下:

1、当到一个时间点时,图上部分的点的最短距离已确定,部分点的最短距离未确定。

2、选一个所有未确定点中离源点最近的点,把他认为成最短距离。

3、再把这个点所有出边遍历一边,更新所有的点。

算法流程:

假设现在要求出某一点s到其他所有点的最短距离,对于每一个点v维护一个“当前距离” dist[v] 和 是否已确定最短距离 st[v]

  1. 初始化距离:首先将 dist[1] 初始化为0,将其他点的距离初始化为正无穷(可以是一个足够大的数)

  2. 迭代计算最短路,迭代 n 次。(有多少个点就循环多少次)

    1. 从所有未确定最短距离的点中,找出当前距离最短的点 t。(遍历dist[],找到未确定最短距离的点中最小的)

    2. t 标记为已确定最短距离的点。(st[t] = true;)

    3. t 来更新其它节点到1号点的距离。

      // 更新其它节点到1号点的距离
      for (int j = 1; j <= n; j++) {
          // 因为当作无向图做,所以不用管,直接判断。没有路的话,g[t][j] = MAX,绝不可能 小于 dist[j]。
          // g 存放每个点之间的距离,g[x][y]表示x->y的距离
          if (dist[t] + g[t][j] < dist[j]) {
              dist[j] = dist[t] + g[t][j];
          }
      }
      
    4. 直到所有的点都已经确定最短距离。这时 dist[] 中存的是1号点到各个点的最短距离。

二、代码实现

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

// 有向图是特殊的无向图

public class M {
	static int N = 510;
	static int MAX = 5000000;
	
	static int n;
	static int m;
	
	// 存每个点之间的距离,g[x][y]表示x->y的距离
	static int[][] g = new int[N][N];
	// 存起点到每个点的距离
	static int[] dist = new int[N];
	// 存已经确定了最短路的点
	static boolean[] st = new boolean[N];
	
	static void dijkstra() {
		
		// 初始化
		Arrays.fill(dist, MAX);
		dist[1] = 0;
		
		// 循环n次,每次可以确定一个最小值
		for (int i = 0; i < n; i++) {
			// 存 离1号点最近的点
			int t = -1;
			// 找到当前距离1号点最近的点
			for (int j = 1; j <= n; j++) {
				/*
				 * 如果该点的最短距离未确定
				 * t = -1 表示刚开始 或者 后面的点比当前的点离1号点更近
				 * 这里不考虑有向图的指向性,当作无向图来判断就行(因为g中没有指向性的两个点之间的长度为正无穷,相当于没路)
				 */
				if (!st[j] && ( t== -1 || dist[j] < dist[t])) {
					// 离1号点最近的点变为j点
					t = j;
				}
			}
			
			// 表示已经找到了确定了最短距离的点t
			st[t] = true;
			
			// 更新其它节点到1号点的距离
			for (int j = 1; j <= n; j++) {
				// 因为当作无向图做,所以不用管,直接判断。没有路的话,g[t][j] = MAX,绝不可能 小于 dist[j]。
				if (dist[t] + g[t][j] < dist[j]) {
					dist[j] = dist[t] + g[t][j];
				}
			}
			
		}
		
		// 如果等于MAX的话,那就说明没有路。输出 -1。
		if (dist[n] == MAX) {
			System.out.println(-1);
		}else {
			System.out.println(dist[n]);
		}
	}

	public static void main(String[] args) throws Exception{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		String[] splits = reader.readLine().split(" ");
		n = Integer.parseInt(splits[0]);
		m = Integer.parseInt(splits[1]);
		
		// 先设定每个点之间的距离都为正无穷
		for (int i = 0; i < g.length; i++) {
			Arrays.fill(g[i], MAX);
		}
		
		
		// 将已有的距离信息填入 g
		for (int i = 1; i <= m; i++) {
			String[] arr = reader.readLine().split(" ");
			int x = Integer.parseInt(arr[0]);
			int y = Integer.parseInt(arr[1]);
			int z = Integer.parseInt(arr[2]);
			
			// 解决重边问题(一个点有两条边指向另一个点,只取最短的一条)
			g[x][y] = Math.min(g[x][y], z);
		}
		
		dijkstra();

	}
}
posted @ 2022-04-03 00:21  KledKled  阅读(49)  评论(0编辑  收藏  举报