Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
一、题目描述:
给定一个 n 个点 m条边的有向图,图中可能存在重边和自环,所有边权均为正值。请你求出 1号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1。
输入格式
第一行包含整数 n 和 m。接下来 m行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z。
输出格式
输出一个整数,表示 1号点到 n号点的最短距离。如果路径不存在,则输出 −1。
数据范围
1≤n≤500, 1≤m≤105, 图中涉及边长均不超过10000。
输入样例:
3 3 1 2 2 2 3 1 1 3 4
输出样例:
3
二、思路分析:
这一题我们需要使用朴素Dijkstra算法,优先使用朴素Dijkstra算法的特点有
- 是单源最短路问题。(起点确定,且只有一个)
- 边的权重都是正数。
- 抽象出来的图为稠密图。
朴素Dijkstra算法的使用步骤
- 初始化距离 :dis[1] = 0,其他点的距离为正无穷
- 开始循环 n - 1次(每次都会确定一个点的最短距离)
- 确定一个目前最短距离的点且没有被放进为最短距离的数组点
- 以这个点为标准更新每个点的距离
- 输出最后目标点的距离
三、AC 代码:
import java.util.Scanner;
/**
* 注意 Integer.MAX_VALUE 加上任意一个整数都会照成数据溢出
*/
public class acwing_849{
/** 图的点数 N 图的边数 M */
static int N,M;
/** 邻接矩阵(存放稠密图) */
static int[][] g = null;
/** 点的距离 */
static int[] dis = null;
/** 已确定点的集合 */
static boolean[] s = null;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
/** 初始化数据 */
N = in.nextInt(); M = in.nextInt();
g = new int[ N + 1 ][ N + 1 ];
dis = new int[ N + 1 ];
s = new boolean[N + 1];
for (int i = 1; i < N + 1; i++) {
for (int j = 1; j < N + 1; j++) {
g[i][j] = 10001;
}
}
for (int i = 0; i < M; i++) {
int a = in.nextInt(); int b = in.nextInt();
g[a][b] = Math.min(in.nextInt(), g[a][b]);
}
dis[1] = 0;
for (int i = 2; i < N + 1; i++) {
dis[i] = 10001;
}
System.out.println(Dijkstra());
}
static int Dijkstra(){
/** 遍历 n - 1 次 ,确定 n - 1 个节点。因为起点已经确定了*/
for (int i = 0; i < N - 1; i++) {
/** t是距离最短的节点,默认要为不存在的下标 */
int t = -1;
/** 找到最短距离且不在已经确定的节点里 */
for (int j = 1; j < N + 1; j++) {
if (!s[j] && (t == -1 || dis[t] > dis[j])) {
t = j;
}
}
/** 利用这个节点来更新距离 */
for (int j = 1; j < N + 1; j++) {
dis[j] = Math.min(dis[j], dis[t] + g[t][j]);
}
/** 把节点放到标志数组里 */
s[t] = true;
}
if(dis[N] == 10001){
return -1;
}
return dis[N];
}
}