目录
每日一句
生活是一只你看不见的储蓄罐,你投入的每一份努力都不会白费
作者简介
🏡个人主页:XiaoChen_Android
📚学习专栏:牛客网
🕒发布日期:2022/8/24
『牛客网||每日一题』米兔走迷宫
1.每日一题
2.解题思路
2.1 思路分析
对于类似于走迷宫找东西的题目,首先就会想到用回溯法,此题只是经典回溯问题的小进化
S1:首先先找到回溯函数需要的几个参数,第一个是方向的参数i和j,第二个就需要一个数组来判断是否访问,第三个就是迷宫的图,最后一个参数就是距离;
S2:接下来要找到不能继续回溯的条件,首先不能越界即,即不能超出迷宫,第二个就是该点没有被访问,第三个就是该点一定要是可走的,即不能为墙;
S3:由于迷宫是有多条路径的,每次找到传送门需要选择最短的路径,所以新增一个变量step来记录每次最短的路径;
S4:四个方向遍历,在遍历完之后要撤销该点已经访问,即改变used数组的值;
S5:在开始走迷宫时,需要先找到迷宫的起点,用两个变量记录该点的坐标,从该点进行回溯;
2.1 核心代码(回溯)
public static void backTrace(char[][] map , int i , int j , boolean[][] used , int ans){
int length = map.length;
int width = map[0].length;
//越界检查 不能是墙# 不能已经走过
if((i < 0 || i >= length || j < 0 || j >= width || map[i][j] == '#' || used[i][j]) == true){
return ;
}
//如果是路,步数++,并记录为已走过
if(map[i][j] == '.' || map[i][j] == '@'){
ans++;
used[i][j] = true;
}
//如果是传送门说明找到一条路径,此时要选择路径短的那条
if(map[i][j] == '$'){
if(ans < step)
step = ans;
return ;
}
backTrace(map,i - 1,j,used,ans);
backTrace(map,i + 1,j,used,ans);
backTrace(map,i,j - 1,used,ans);
backTrace(map,i,j + 1,used,ans);
used[i][j] = false;
}
2.3 完整代码
import java.util.Scanner;
public class Main5 {
static int step = 99999;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int width = sc.nextInt();
int length = sc.nextInt();
char[][] map = new char[length][width];
boolean[][] used = new boolean[length][width];
String[] str = new String[length];
for(int i = 0 ; i < length ; i++){
str[i] = sc.next();
}
int idx = 0,idy = 0;
for(int i = 0 ; i < length ; i++){
for(int j = 0 ; j < width ; j++){
used[i][j] = false;
map[i][j] = str[i].charAt(j);
if(map[i][j] == '@'){
idx = i;
idy = j;
}
}
}
//记录每次路径的长度
int ans = 1;
backTrace(map,idx,idy,used,ans);
System.out.println(step);
}
public static void backTrace(char[][] map , int i , int j , boolean[][] used , int ans){
int length = map.length;
int width = map[0].length;
//越界检查 不能是墙# 不能已经走过
if((i < 0 || i >= length || j < 0 || j >= width || map[i][j] == '#' || used[i][j]) == true){
return ;
}
//如果是路,步数++,并记录为已走过
if(map[i][j] == '.' || map[i][j] == '@'){
ans++;
used[i][j] = true;
}
//如果是传送门说明找到一条路径,此时要选择路径短的那条
if(map[i][j] == '$'){
if(ans < step)
step = ans;
return ;
}
backTrace(map,i - 1,j,used,ans);
backTrace(map,i + 1,j,used,ans);
backTrace(map,i,j - 1,used,ans);
backTrace(map,i,j + 1,used,ans);
used[i][j] = false;
}
}
2.4 运行结果
2.5 官方答案
import java.util.Scanner;
public class Main {
static int h, w;
static int startX, startY;
static int count;
static int[][] map;
static int[][] visit;
static int min;
static final int move[][] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public static void dfs(int x, int y) {
count++;
visit[x][y] = 1;
if (map[x][y] == 3) {
if (count < min) {
min = count;
}
return;
}
if (count >= min) {
return;
}
for (int i = 0; i < 4; i++) {
int newX = x + move[i][0];
int newY = y + move[i][1];
if (check(newX, newY)) {
dfs(newX, newY);
count--;
visit[newX][newY] = 0;
}
}
}
public static boolean check(int x, int y) {
return x >= 0 && x < h && y >= 0 && y < w && map[x][y] != 0 && visit[x][y] == 0;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
w = sc.nextInt();
h = sc.nextInt();
map = new int[h][w];
visit = new int[h][w];
min = h*w;
count = 0;
for (int i = 0; i < h; i++) {
String temp = sc.next();
for (int j = 0; j < w; j++) {
char a = temp.charAt(j);
switch (a) {
case '#':
map[i][j] = 0;
break;
case '.':
map[i][j] = 1;
break;
case '@':
map[i][j] = 2;
startX = i;
startY = j;
break;
case '$':
map[i][j] = 3;
break;
}
}
}
dfs(startX, startY);
System.out.println(min);
sc.close();
}
}
我的答案仅供参考,各位大佬有更好的方法可以分享出来
🍁 类似题目推荐:
如果文章对各位大佬有帮助就支持一下噢,新手尝试,不好的地方请各位大佬多多指教!