问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点。
单源最短路问题,之前没有做过,找了个视频看,之后先写出了根据Bellman-ford算法的代码,只能得80分,代码如下
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int m=scanner.nextInt();
int[] u=new int[m+1];//装入每条边的起点
int[] v=new int[m+1];//装入每条边的终点
int[] w=new int[m+1];//装入每条边的权值
int[] d=new int[n+1];//装入从原点到各点的最短路,会首先初始化为无穷
//填入每条边的起点、终点、权值
for (int i = 1; i <= m; i++) {
u[i]=scanner.nextInt();
v[i]=scanner.nextInt();
w[i]=scanner.nextInt();
}
//对d数组初始化,减10000是因为如果用int的最大值去计算,会算出负数,需要预留出一定的空间
去加上边的权值
for (int i = 1; i <= n; i++) {
d[i]=Integer.MAX_VALUE-10000;
}
//本题起点为1,所以起点到起点的长度为0,即d[1]=0
d[1]=0;
//Bellman-ford算法思想,对边进行松弛
for (int i = 1; i < n; i++) {
for (int j = 1; j <= m; j++) {
if (d[v[j]]>d[u[j]]+w[j]){
d[v[j]]=d[u[j]]+w[j];
}
}
}
for (int i = 2; i <= n; i++) {
System.out.println(d[i]);
}
}
}
继续优化, 写出如下代码,发现已经能满分了
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n=scanner.nextInt();
int m=scanner.nextInt();
int[] u=new int[m+1];//装入每条边的起点
int[] v=new int[m+1];//装入每条边的终点
int[] w=new int[m+1];//装入每条边的权值
int[] d=new int[n+1];//装入从原点到各点的最短路,会首先初始化为无穷
//填入每条边的起点、终点、权值
for (int i = 1; i <= m; i++) {
u[i]=scanner.nextInt();
v[i]=scanner.nextInt();
w[i]=scanner.nextInt();
}
//对d数组初始化,减10000是因为如果用int的最大值去计算,会算出负数,需要预留出一定的空间
去加上边的权值
for (int i = 1; i <= n; i++) {
d[i]=Integer.MAX_VALUE-10000;
}
//本题起点为1,所以起点到起点的长度为0,即d[1]=0
d[1]=0;
//Bellman-ford算法思想,对边进行松弛
for (int i = 1; i < n; i++) {
//设置一个标志,如果某一次d数组不再变化,那么以后数组都不会再变化,说明已经找到了最
短路,那么这个时候就可以跳出循环
int flag=0;
for (int j = 1; j <= m; j++) {
if (d[v[j]]>d[u[j]]+w[j]){
d[v[j]]=d[u[j]]+w[j];
flag=1;
}
if(flag==0){
break;
}
}
}
for (int i = 2; i <= n; i++) {
System.out.println(d[i]);
}
}
}
学习参考的视频链接:SPFA算法讲解_哔哩哔哩_bilibili