华为OD机试 - 按图找最近的路 - 探索路径并标记

题目

有一张m*n的地图,地图描述了起点和终点的位置,也描述了两点间分布的高山湖泊,高山湖泊挡住去路,需要绕道行走,请问从起点到终点的最短路径有几条,距离是多少?

示例

输入说明:
5 5 ——图的大小
0 1 ——起点坐标
3 3 ——终点坐标
1 ——湖泊个数
2 2 ——湖泊坐标
输出说明:
最短路径有4条,距离是5,输出格式是 4 5

解题过程

  1. 涉及到路径问题,只能穷举
  2. 每个坐标都有上下左右的探索方向,以坐标1,1为例,向右则x+1,1,向上则x,y+1;向下则x, y-1;向左则x-1,y所以,初始化x和y的变化矩阵
static int[] DX = {0, 1, 0, -1};
static int[] DY = {1, 0, -1, 0};
  1. 初始化探索矩阵和地图矩阵
    探索矩阵:探索的地图为1,未探索的为0
    地图矩阵:障碍的坐标为2,非障碍为1

完整代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class Test016 {
    /*
     * 按图找最近的路 - 矩阵、最短路径问题
     * 输入表示:
     * 5 5 ——图的大小
     * 0 1 ——起点坐标
     * 3 3 ——终点坐标
     * 1 ——湖泊个数
     * 2 2 ——湖泊坐标
     * 最短路径有4条,距离是5,输出格式是 4 5
     * */
    static int STEP_MIN = Integer.MAX_VALUE;
    // 探索位移的方向
    static int[] DX = {0, 1, 0, -1};
    static int[] DY = {1, 0, -1, 0};
    // 位移距离和对应的路径坐标
    static Map<Integer, List<int[][]>> STEP_MAP = new HashMap<>();

    public static void main(String[] args) {
        try {
            Scanner sc = new Scanner(System.in);
            String[] split = sc.nextLine().split(" ");
            int x = Integer.parseInt(split[0]);
            int y = Integer.parseInt(split[1]);
            if (y < 0 || x < 0) {
                System.out.println("error");
                return;
            }
            // 起点
            int[] start = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
            // 终点
            int[] end = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
            // 障碍点
            int obstacleCount = Integer.parseInt(sc.nextLine());
            List<String> obstacleMap = new ArrayList<>();
            for (int i = 0; i < obstacleCount; i++) {
                obstacleMap.add(sc.nextLine());
            }
            int[][] arrMap = new int[x][y];
            int[][] loadMap = new int[x][y];
            // 构建地图坐标和障碍坐标
            // 定义探索的地图为1,未探索的为0
            // 定义障碍的坐标为2,非障碍为1
            for (int i = 0; i < x; i++) {
                for (int j = 0; j < y; j++) {
                    // 障碍为2
                    String temp = String.join(" ", String.valueOf(i), String.valueOf(j));
                    if (obstacleMap.contains(temp)) {
                        arrMap[i][j] = 2;
                    } else {
                        arrMap[i][j] = 1;
                    }
                    // 探索路径,0未探索
                    loadMap[i][j] = 0;
                }
            }
            for (int i = 0; i < 4; i++) {
                int step = 0;
                nextStep(i, start, step, end, arrMap, loadMap);
            }
            if (STEP_MAP.isEmpty()) {
                System.out.println("没有路径可达");
            }
            List<Integer> integers = new ArrayList<>(STEP_MAP.keySet());
            // 取最短路径
            Collections.sort(integers);
            System.out.println(STEP_MAP.get(integers.get(0)).size() + " " + integers.get(0));
            for (int[][] node : STEP_MAP.get(integers.get(0))) {
                Arrays.asList(node).forEach(load ->
                    System.out.print("(" + load[0] + "," + load[1] + "),"));
                System.out.println();
            }
        } catch (Exception e) {
            System.out.println("ERROR");
        }
    }

    private static void dfs(int[] tempStart,
        int step, int[] end, int[][] arrMap, int[][] loadMap) {
        // 已探索的路径步进数量量小于当前步进,则此路径不需要继续,返回
        // 如果需要探明各种步进的数量和路径,则此判断可移除
        if (STEP_MIN < step) {
            return;
        }
        // 位移到目标地址
        if (tempStart[0] == end[0] && tempStart[1] == end[1]) {
                STEP_MIN = step;
                int[][] loadArea = new int[step][2];
                // 遍历探索路径,不为0则表示属于探索路径,收集路径节点
                // 因题目未要求,所以未按路径顺序收集坐标
                for (int i = 0; i < loadMap.length; i++) {
                    for (int j = 0; j < loadMap[i].length; j++) {
                        if (loadMap[i][j] == 0) {
                            continue;
                        }
                        loadArea[loadMap[i][j] - 1] = new int[]{i, j};
                    }
                }
                List<int[][]> orDefault = STEP_MAP.getOrDefault(step, new ArrayList<>());
                orDefault.add(loadArea);
                STEP_MAP.put(step, orDefault);
                return;
        }
        for (int i = 0; i < 4; i++) {
            nextStep(i, tempStart, step, end, arrMap, loadMap);
        }
    }

    public static void nextStep(int i,
        int[] tempStart, int step, int[] end, int[][] arrMap, int[][] loadMap) {
        int tempX = tempStart[0] + DX[i];
        int tempY = tempStart[1] + DY[i];
        // 越界
        if (tempX < 0 || tempX >= arrMap.length
            || tempY < 0 || tempY >= arrMap[0].length) {
            return;
        }
       
        // 定义障碍的坐标为2,非障碍为1
        // 如果当前地址是未探索的,非障碍物,则继续探索
        if (arrMap[tempX][tempY] == 1 && loadMap[tempX][tempY] == 0) {
         	// 定义探索的地图路径顺序,未探索的为0
            loadMap[tempX][tempY] = step + 1;
            dfs(new int[]{tempX, tempY}, step + 1, end, arrMap, loadMap);
            // 探索完成,恢复地图
            loadMap[tempX][tempY] = 0;
        }
    }
}

如果有更好的思路或优化方向,欢迎评论,顺便帮忙点个赞,谢谢。
Alt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值