题目
有一张m*n的地图,地图描述了起点和终点的位置,也描述了两点间分布的高山湖泊,高山湖泊挡住去路,需要绕道行走,请问从起点到终点的最短路径有几条,距离是多少?
示例
输入说明:
5 5 ——图的大小
0 1 ——起点坐标
3 3 ——终点坐标
1 ——湖泊个数
2 2 ——湖泊坐标
输出说明:
最短路径有4条,距离是5,输出格式是 4 5
解题过程
- 涉及到路径问题,只能穷举
- 每个坐标都有上下左右的探索方向,以坐标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,未探索的为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;
}
}
}
如果有更好的思路或优化方向,欢迎评论,顺便帮忙点个赞,谢谢。