Floyd 算法 Java
图论算法实践:使用 Floyd 求任意两点最短路(Java 实现)
在图论算法中,Floyd-Warshall 算法是一个经典的动态规划算法,用于在一个加权图中寻找所有点对之间的最短路径。
场景描述
假设我们有一个包含 n
个点的无向图,图中有 m
条边,每条边连接两个点并带有一定的权重。我们还需要回答 q
个询问,每个询问是从点 x
到点 y
的最短路径长度。如果两点之间不可达,输出 -1
。
解决方案:Floyd-Warshall 算法
Floyd-Warshall 是一个三重循环的动态规划算法,时间复杂度为 O(n^3),适用于点数较少的图。
核心思想
我们维护一个 dist[i][j]
数组,表示从点 i
到点 j
的最短路径长度。初始时,dist[i][j]
设为边权(或正无穷),然后不断尝试通过中转点 k
来优化从 i
到 j
的路径。
Java 实现代码
// 包名可自定义
package ff;
import java.io.*;
import java.util.*;
public class Main {
static FastRead in = new FastRead();
static PrintWriter out = new PrintWriter(System.out);
public static void main(String[] args) {
int n = in.nextInt(); // 点数
int m = in.nextInt(); // 边数
int q = in.nextInt(); // 查询数
long[][] dist = new long[n + 1][n + 1];
// 初始化邻接矩阵
for (int i = 1; i <= n; i++) {
Arrays.fill(dist[i], Long.MAX_VALUE);
dist[i][i] = 0; // 自己到自己距离为0
}
// 读入边并更新最短路径(无向图)
while (m-- > 0) {
int u = in.nextInt();
int v = in.nextInt();
long w = in.nextLong();
dist[u][v] = Math.min(dist[u][v], w);
dist[v][u] = Math.min(dist[v][u], w);
}
// 核心算法:Floyd-Warshall 三重循环
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (dist[i][k] != Long.MAX_VALUE && dist[k][j] != Long.MAX_VALUE) {
dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
}
// 处理查询
while (q-- > 0) {
int x = in.nextInt();
int y = in.nextInt();
out.println(dist[x][y] != Long.MAX_VALUE ? dist[x][y] : -1);
}
out.flush();
out.close();
}
}
辅助类 FastRead
为了提升输入效率,使用了封装的快速读入类:
class FastRead {
StringTokenizer st;
BufferedReader br;
public FastRead() {
br = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
double nextDouble() {
return Double.parseDouble(next());
}
long nextLong() {
return Long.parseLong(next());
}
String nextLine() {
String str = null;
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
}
示例输入输出说明
假设输入为:
4 5 3
1 2 3
2 3 4
3 4 5
4 1 2
1 3 10
1 3
2 4
1 4
输出应为:
7
9
2
注意事项
-
边可能有重边,需取最小值处理。
-
初始化时要小心:
dist[i][j] = Long.MAX_VALUE
会导致溢出问题,必须判断是否为MAX_VALUE
再加法。 -
点编号从 1 开始,数组大小应为
n + 1
。
总结
Floyd-Warshall 是处理稠密图、所有点对路径问题的强力工具,使用简单,效率可接受。
如果你喜欢这样的算法详解,也欢迎点赞、收藏或留言交流!