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.

238 lines
7.2 KiB

2 years ago
package class44;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
public class Problem_0317_ShortestDistanceFromAllBuildings {
// 如果grid中0比较少用这个方法比较好
public static int shortestDistance1(int[][] grid) {
int ans = Integer.MAX_VALUE;
int N = grid.length;
int M = grid[0].length;
int buildings = 0;
Position[][] positions = new Position[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (grid[i][j] == 1) {
buildings++;
}
positions[i][j] = new Position(i, j, grid[i][j]);
}
}
if (buildings == 0) {
return 0;
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
ans = Math.min(ans, bfs(positions, buildings, i, j));
}
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
public static int bfs(Position[][] positions, int buildings, int i, int j) {
if (positions[i][j].v != 0) {
return Integer.MAX_VALUE;
}
HashMap<Position, Integer> levels = new HashMap<>();
Queue<Position> queue = new LinkedList<>();
Position from = positions[i][j];
levels.put(from, 0);
queue.add(from);
int ans = 0;
int solved = 0;
while (!queue.isEmpty() && solved != buildings) {
Position cur = queue.poll();
int level = levels.get(cur);
if (cur.v == 1) {
ans += level;
solved++;
} else {
add(queue, levels, positions, cur.r - 1, cur.c, level + 1);
add(queue, levels, positions, cur.r + 1, cur.c, level + 1);
add(queue, levels, positions, cur.r, cur.c - 1, level + 1);
add(queue, levels, positions, cur.r, cur.c + 1, level + 1);
}
}
return solved == buildings ? ans : Integer.MAX_VALUE;
}
public static class Position {
public int r;
public int c;
public int v;
public Position(int row, int col, int value) {
r = row;
c = col;
v = value;
}
}
public static void add(Queue<Position> q, HashMap<Position, Integer> l, Position[][] p, int i, int j, int level) {
if (i >= 0 && i < p.length && j >= 0 && j < p[0].length && p[i][j].v != 2 && !l.containsKey(p[i][j])) {
l.put(p[i][j], level);
q.add(p[i][j]);
}
}
// 如果grid中1比较少用这个方法比较好
public static int shortestDistance2(int[][] grid) {
int N = grid.length;
int M = grid[0].length;
int ones = 0;
int zeros = 0;
Info[][] infos = new Info[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (grid[i][j] == 1) {
infos[i][j] = new Info(i, j, 1, ones++);
} else if (grid[i][j] == 0) {
infos[i][j] = new Info(i, j, 0, zeros++);
} else {
infos[i][j] = new Info(i, j, 2, Integer.MAX_VALUE);
}
}
}
if (ones == 0) {
return 0;
}
int[][] distance = new int[ones][zeros];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (infos[i][j].v == 1) {
bfs(infos, i, j, distance);
}
}
}
int ans = Integer.MAX_VALUE;
for (int i = 0; i < zeros; i++) {
int sum = 0;
for (int j = 0; j < ones; j++) {
if (distance[j][i] == 0) {
sum = Integer.MAX_VALUE;
break;
} else {
sum += distance[j][i];
}
}
ans = Math.min(ans, sum);
}
return ans == Integer.MAX_VALUE ? -1 : ans;
}
public static class Info {
public int r;
public int c;
public int v;
public int t;
public Info(int row, int col, int value, int th) {
r = row;
c = col;
v = value;
t = th;
}
}
public static void bfs(Info[][] infos, int i, int j, int[][] distance) {
HashMap<Info, Integer> levels = new HashMap<>();
Queue<Info> queue = new LinkedList<>();
Info from = infos[i][j];
add(queue, levels, infos, from.r - 1, from.c, 1);
add(queue, levels, infos, from.r + 1, from.c, 1);
add(queue, levels, infos, from.r, from.c - 1, 1);
add(queue, levels, infos, from.r, from.c + 1, 1);
while (!queue.isEmpty()) {
Info cur = queue.poll();
int level = levels.get(cur);
distance[from.t][cur.t] = level;
add(queue, levels, infos, cur.r - 1, cur.c, level + 1);
add(queue, levels, infos, cur.r + 1, cur.c, level + 1);
add(queue, levels, infos, cur.r, cur.c - 1, level + 1);
add(queue, levels, infos, cur.r, cur.c + 1, level + 1);
}
}
public static void add(Queue<Info> q, HashMap<Info, Integer> l, Info[][] infos, int i, int j, int level) {
if (i >= 0 && i < infos.length && j >= 0 && j < infos[0].length && infos[i][j].v == 0
&& !l.containsKey(infos[i][j])) {
l.put(infos[i][j], level);
q.add(infos[i][j]);
}
}
// 方法三的大流程和方法二完全一样从每一个1出发而不从0出发
// 运行时间快主要是因为常数优化,以下是优化点:
// 1) 宽度优先遍历时,一次解决一层,不是一个一个遍历:
// int size = que.size();
// level++;
// for (int k = 0; k < size; k++) { ... }
// 2) pass的值每次减1何用只有之前所有的1都到达的0才有必要继续尝试的意思
// 也就是说如果某个1自我封闭之前的1根本到不了现在这个1附近的0就没必要继续尝试了
// if (nextr >= 0 && nextr < grid.length
// && nextc >= 0 && nextc < grid[0].length
// && grid[nextr][nextc] == pass)
// 3) int[] trans = { 0, 1, 0, -1, 0 }; 的作用是迅速算出上、下、左、右
// 4) 如果某个1在计算时它周围已经没有pass值了可以提前宣告1之间是不连通的
// step = bfs(grid, dist, i, j, pass--, trans);
// if (step == Integer.MAX_VALUE) {
// return -1;
// }
// 5) 最要的优化每个1到某个0的距离是逐渐叠加的每个1给所有的0叠一次宽度优先遍历
// dist[nextr][nextc] += level;
public static int shortestDistance3(int[][] grid) {
int[][] dist = new int[grid.length][grid[0].length];
int pass = 0;
int step = Integer.MAX_VALUE;
int[] trans = { 0, 1, 0, -1, 0 };
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
step = bfs(grid, dist, i, j, pass--, trans);
if (step == Integer.MAX_VALUE) {
return -1;
}
}
}
}
return step == Integer.MAX_VALUE ? -1 : step;
}
// 原始矩阵是grid但是所有的路(0),被改了
// 改成了啥改成认为pass才是路原始矩阵中的1和2呢不变
// dist距离压缩表之前的bfs也就是之前每个1走到某个0总距离和都在dist里
// row,col 宽度优先遍历的,出发点!
// trans -> 炫技的,上下左右
// 返回值代表进行完这一遍bfs压缩距离表中(dist),最小值是谁?
// 如果突然发现,无法联通!返回系统最大!
public static int bfs(int[][] grid, int[][] dist, int row, int col, int pass, int[] trans) {
Queue<int[]> que = new LinkedList<int[]>();
que.offer(new int[] { row, col });
int level = 0;
int ans = Integer.MAX_VALUE;
while (!que.isEmpty()) {
int size = que.size();
level++;
for (int k = 0; k < size; k++) {
int[] node = que.poll();
for (int i = 1; i < trans.length; i++) { // 上下左右
int nextr = node[0] + trans[i - 1];
int nextc = node[1] + trans[i];
if (nextr >= 0 && nextr < grid.length && nextc >= 0 && nextc < grid[0].length
&& grid[nextr][nextc] == pass) {
que.offer(new int[] { nextr, nextc });
dist[nextr][nextc] += level;
ans = Math.min(ans, dist[nextr][nextc]);
grid[nextr][nextc]--;
}
}
}
}
return ans;
}
}