You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_12_4_week;
// Floyd算法应用
// 存在一个由 n 个节点组成的无向连通图,图中的节点按从 0 到 n - 1 编号
// 给你一个数组 graph 表示这个图
// 其中graph[i] 是一个列表,由所有与节点 i 直接相连的节点组成
// 返回能够访问所有节点的最短路径的长度
// 你可以在任一节点开始和停止,也可以多次重访节点,并且可以重用边
// 测试链接 : https://leetcode.cn/problems/shortest-path-visiting-all-nodes/
public class Code03_ShortestPathVisitingAllNodes {
public static int shortestPathLength(int[][] graph) {
int n = graph.length;
int[][] distance = floyd(n, graph);
int ans = Integer.MAX_VALUE;
int[][] dp = new int[1 << n][n];
for (int i = 0; i < (1 << n); i++) {
for (int j = 0; j < n; j++) {
dp[i][j] = -1;
}
}
for (int i = 0; i < n; i++) {
ans = Math.min(ans, process(1 << i, i, n, distance, dp));
}
return ans;
}
public static int[][] floyd(int n, int[][] graph) {
int[][] distance = new int[n][n];
// 初始化认为都没路
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
distance[i][j] = Integer.MAX_VALUE;
}
}
// 自己到自己的距离为0
for (int i = 0; i < n; i++) {
distance[i][i] = 0;
}
// 支持任意有向图,把直接边先填入
for (int cur = 0; cur < n; cur++) {
for (int next : graph[cur]) {
distance[cur][next] = 1;
distance[next][cur] = 1;
}
}
// O(N^3)的过程
// 枚举每个跳板
// 注意! 跳板要最先枚举然后是from和to
for (int jump = 0; jump < n; jump++) {
for (int from = 0; from < n; from++) {
for (int to = 0; to < n; to++) {
if (distance[from][jump] != Integer.MAX_VALUE && distance[jump][to] != Integer.MAX_VALUE
&& distance[from][to] > distance[from][jump] + distance[jump][to]) {
distance[from][to] = distance[from][jump] + distance[jump][to];
}
}
}
}
return distance;
}
// status : 所有已经走过点的状态
// 0 1 2 3 4 5
// int
// 5 4 3 2 1 0
// 0 0 1 1 0 1
// cur : 当前所在哪个城市!
// n : 一共有几座城
// 返回值 : 从此时开始,逛掉所有的城市,至少还要走的路,返回!
public static int process(int status, int cur, int n, int[][] distance, int[][] dp) {
// 5 4 3 2 1 0
// 1 1 1 1 1 1
// 1 << 6 - 1
if (status == (1 << n) - 1) {
return 0;
}
if (dp[status][cur] != -1) {
return dp[status][cur];
}
int ans = Integer.MAX_VALUE;
// status:
// 5 4 3 2 1 0
// 0 0 1 0 1 1
// cur : 0
// next : 2 4 5
for (int next = 0; next < n; next++) {
if ((status & (1 << next)) == 0 && distance[cur][next] != Integer.MAX_VALUE) {
int nextAns = process(status | (1 << next), next, n, distance, dp);
if (nextAns != Integer.MAX_VALUE) {
ans = Math.min(ans, distance[cur][next] + nextAns);
}
}
}
dp[status][cur] = ans;
return ans;
}
}