写完才发现这个题目 保证有且只有一条到出口的路 是我想复杂了 QAQ
import java.util.*; /** * @author hll[yellowdradra@foxmail.com] * @date 2022-10-09 14:43 **/ public class Main { /** * 上 */ final static int TOP = 0; /** * 右 */ final static int RIGHT = 1; /** * 下 */ final static int BOTTOM = 2; /** * 左 */ final static int LEFT = 3; /** * 迷宫行数 */ static int N; /** * 迷宫列数 */ static int M; /** * 迷宫数组 为true表示能走 false表示不能走 */ static boolean[][] maze; /** * 存储所有的路径 */ static List<Set<Point>> paths = new ArrayList<>(); /** * 终点 */ static Point END_POINT; public static void main(String[] args) { Scanner in = new Scanner(System.in); N = in.nextInt(); M = in.nextInt(); maze = new boolean[N][M]; END_POINT = new Point(N - 1, M - 1); for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { maze[i][j] = in.nextInt() == 0; } } // Set保证没有环形路径 环形路径会导致死循环 // LinkedHashSet保证输入顺序 Set<Point> p = new LinkedHashSet<>(); go(new Point(0, 0), p); for (Set<Point> path : paths) { // 路径的末尾是终点的话 那这是一条可行路径 打印这条路径 if (path.contains(END_POINT)) { path.forEach(System.out::println); } } } /** * * @param point 目标点 * @param path 到目标点之前的路径 */ static void go(Point point, Set<Point> path) { Set<Point> newPath = new LinkedHashSet<>(path); newPath.add(point); // 如果到了终点 则立即停止探索 将路径添加至路径列表 if (point.equals(END_POINT)) { paths.add(newPath); return; } boolean isEndPoint = true; // 顺时针探索是否有可以前进的点 for (int d = TOP; d <= LEFT; d++) { Point nextPoint = nextPoint(point, d, newPath); if (nextPoint != null) { isEndPoint = false; go(nextPoint, newPath); } } // 如果没有可以前进的点 那么本次探索结束 if (isEndPoint) { paths.add(newPath); } } /** * @param point 当前所处点位 * @param direction 探索方向 * @param path 已经走过的路径 * @return */ static Point nextPoint(Point point, int direction, Set<Point> path) { int n = point.x, m = point.y; boolean isOverBorder = false; switch (direction) { case TOP: isOverBorder = --n < 0; break; case RIGHT: isOverBorder = ++m >= M; break; case BOTTOM: isOverBorder = ++n >= N; break; case LEFT: isOverBorder = --m < 0; break; default: break; } Point nextPoint = new Point(n, m); // 如果 没有超出迷宫边界 && 该点位不是墙 && 没有走过该点 则这个点是可达的 if (!isOverBorder && maze[n][m] && !path.contains(nextPoint)) { return nextPoint; } return null; } /** * 因为要将这个Point类放进Set 所以要重写equals和hashcode方法 * 顺便重写一些toString方法 方便输出 牛客的JDK是1.8 高版本的JDK可以用Record实现Point 更简便 */ static class Point { int x, y; Point(int x, int y) { this.x = x; this.y = y; } @Override public String toString() { return "(" + x + "," + y + ")"; } @Override public boolean equals(Object obj) { Point p = (Point) obj; if (p.x == this.x && p.y == this.y) { return true; } return false; } @Override public int hashCode() { return this.toString().hashCode(); } } }
--------------------------------2024-07-11 更新分割线----------------------------
今天无事 摸鱼中 重写了这道题 用的jdk17
/** * <a href="https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc">迷宫问题</a> * * @author hll[yellowdradra@foxmail.com] * @since 2024/07/11 */ public record Point(int x, int y) { /** * 按照题目要求的格式输出路径上的每个点 * @return 点 */ @Override public String toString() { return "(" + x + "," + y + ")"; } }
/** * <a href="https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc">迷宫问题</a> * <p>方向</p> * * @author hll[yellowdradra@foxmail.com] * @since 2024/07/11 **/ public enum Direction { /** 向上 */ UP, /** 向下 */ DOWN, /** 向左 */ LEFT, /** 向右 */ RIGHT }
import lombok.Data; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; /** * <a href="https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc">迷宫问题</a> * <p>迷宫</p> * * @author hll[yellowdradra@foxmail.com] * @since 2024/07/11 **/ @Data public class Maze { /** 不可以走的墙 */ private static final int WALL = 1; /** 可以走的路 */ private static final int ROAD = 0; /** 迷宫行数 */ private final int n; /** 迷宫列数 */ private final int m; /** 迷宫数组 true: 能走 false: 不能走 */ private final Integer[][] map; /** 存储所有的路径 */ private final List<Set<Point>> paths; /** 终点 */ private final Point endPoint; public Maze(int n, int m, Integer[][] map) { this.n = n; this.m = m; this.map = map; this.paths = new ArrayList<>(); this.endPoint = new Point(n - 1, m - 1); // LinkedHashSet Linked保证每个点的顺序 Set保证不重复走一个点 search(new Point(0, 0), new LinkedHashSet<>()); } /** * 数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。 */ public void printRightPath() { for (Set<Point> path : getPaths()) { // 路径的末尾是终点的话 那这是一条可行路径 打印这条路径 if (path.contains(getEndPoint())) { path.forEach(System.out::println); } } } /** * @param point 目标点 * @param path 到目标点之前的路径 */ private void search(Point point, Set<Point> path) { Set<Point> newPath = new LinkedHashSet<>(path); newPath.add(point); // 如果到了终点 则立即停止探索 将路径添加至路径列表 if (point.equals(getEndPoint())) { getPaths().add(newPath); return; } boolean isEndPoint = true; // 向每个方向探索 for (Direction direction : Direction.values()) { Point nextPoint = nextPoint(point, direction, newPath); if (nextPoint != null) { isEndPoint = false; search(nextPoint, newPath); } } // 如果没有可以前进的点 那么本次探索结束 if (isEndPoint) { getPaths().add(newPath); } } /** * @param point 当前所处点位 * @param direction 探索方向 * @param path 已经走过的路径 * @return 如果下一个点存在则返回下一个点 否则返回 null */ private Point nextPoint(Point point, Direction direction, Set<Point> path) { int x = point.x(), y = point.y(); boolean isOverBorder = false; switch (direction) { case UP: isOverBorder = --x < 0; break; case RIGHT: isOverBorder = ++y >= this.m; break; case DOWN: isOverBorder = ++x >= this.n; break; case LEFT: isOverBorder = --y < 0; break; default: break; } Point nextPoint = new Point(x, y); // 如果 没有超出迷宫边界 且 该点位不是墙 且 没有走过该点 则这个点是可达的 if (!isOverBorder && map[x][y] == ROAD && !path.contains(nextPoint)) { return nextPoint; } return null; } }
import java.util.*; /** * <a href="https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc">迷宫问题</a> * * @author hll[yellowdradra@foxmail.com] * @since 2024/07/11 **/ public class HJ43 { public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); Maze maze = new Maze(n, m, ScannerUtils.scanInt2DArray(in, n, m)); maze.printRightPath(); } }
每次写从scanner接收输入的代码太麻烦了 写了个工具类
import lombok.experimental.UtilityClass; import java.lang.reflect.Array; import java.util.Scanner; /** * 扫描器工具类 * * @author hll * @since 2024/07/10 */ @UtilityClass public class ScannerUtils { public <T> T[] scanArray(Scanner sc, Class<T> clazz) { return scanArray(sc, clazz, sc.nextInt()); } @SuppressWarnings("unchecked") public <T> T[] scanArray(Scanner sc, Class<T> clazz, int n) { T[] array = (T[]) Array.newInstance(clazz, n); for (int i = 0; i < n; i++) { String val = sc.next(); if (clazz == String.class) { array[i] = (T) val; } else if (clazz == Integer.class) { array[i] = (T) Integer.valueOf(val); } } return array; } public Integer[][] scanInt2DArray(Scanner sc, int rows, int cols) { Integer[][] array = new Integer[rows][]; for (int i = 0; i < rows; i++) { array[i] = scanArray(sc, Integer.class, cols); } return array; } }