迷宫问题总结(算法)

1、常见迷宫问题

回溯、dfs:是否有解,唯一解等问题

//递归写法
    public static boolean dfs(char[][] m, boolean[][] vis, Node start, Node end) {
        if (start.x == end.x && start.y == end.y) {
            return true;
        }
        vis[start.x][start.y] = true;

        for (int i = 0; i < 4; i++) {
            int x = start.x + xx[i];
            int y = start.y + yy[i];
            if (check(m, vis, x, y)) {
                if (dfs(m, vis, new Node(x, y), end) )  //有一个trur就行了
                    return true;
            }
        }
        return false;
    }
    
    //栈模拟写法
    public static boolean dfs2(char[][] m, boolean[][] vis, Node start, Node end) {
        vis[start.x][start.y] = true;

        Deque<Node> st = new LinkedList<>();  //模拟栈
        st.push(start);
        while (!st.isEmpty()) {
            Node tmp = st.pop();
            if (tmp.x == end.x && tmp.y == end.y) {
                return true;
            }
            vis[tmp.x][tmp.y] = true;
            //tmp.print();
            for (int i = 0; i < 4; i++) {
                int x = tmp.x + xx[i];
                int y = tmp.y + yy[i];
                if (check(m, vis, x, y)) {
                    st.push(new Node(x, y));
                }
            }
        }
        return false;
    }

BFS:走出迷宫的最短路径:

class Node {
    int x, y;
    //int len; //有时需要记录深度
    //Node pre; //有事需要记录路劲
}

public static int BFS(char[][] m, boolean[][] vis, Node start, Node end,) {
        Queue<Node> q = new LinkedList<>();
        q.offer(new Node(start.x, start.y, 0));   // 起点加入队列
        while (!q.isEmpty()) {
            Node tmp = q.poll();
            vis[tmp.x][tmp.y] = true;
            if (tmp.x == end.x && tmp.y == end.y) {  //到大终点
                return tmp.len;
            }
            for (int i = 0; i < 4; i++) {      // 上下左右四个方向 并检查坐标的合法性及是否访问
                int x = tmp.x + xx[i];
                int y = tmp.y + yy[i];
                if (check(m, vis, x, y, c)) {
                    Node newTmp = new Node(x, y, tmp.len + 1);
                    q.offer(newTmp);
                }
            }

        }
        return -1;
    }

2、一道难题

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

这是一个关于二维迷宫的题目。我们要从迷宫的起点 'S' 走到终点 'E',每一步我们只能选择上下左右四个方向中的一个前进一格。 'W' 代表墙壁,是不能进入的位置,除了墙壁以外的地方都可以走。迷宫内的 'D' 代表一道上锁的门,只有在持有钥匙的时候才能进入。而 'K' 则代表了钥匙,只要进入这一格,就会自动地拿到钥匙。最后 '.' 则是代表空无一物的地方,欢迎自在的游荡。

本题的迷宫中,起点、终点、门跟钥匙这四个特殊物件,每一个恰好会出现一次。而且,此迷宫的四周 (最上面的一行、最下面的一行、最左边的一列以及最右边的一列) 都会是墙壁。

请问,从起点到终点,最少要走几步呢?

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

class Node {
    int x, y, len;

    public Node(int a, int b, int l) {
        x = a;
        y = b;
        len = l;
    }

    public Node() {
    }

    public void print() {
        System.out.println(x + " " + y + " " + len);
    }
}

public class Main {
    static int[] xx = new int[]{1, 0, -1, 0};
    static int[] yy = new int[]{0, 1, 0, -1};

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt();
        int n = in.nextInt();

        char[][] a = new char[m][n];
        boolean[][] vis = new boolean[m][n];
        in.nextLine();

        Node start = new Node(), end = new Node(-1, -1, 0), key = new Node(-1, -1, 0), men = new Node(-1, -1, 0);
        for (int i = 0; i < m; i++) {
            String s = in.nextLine();
            for (int j = 0; j < n; j++) {
                a[i][j] = s.charAt(j);
                if (s.indexOf('S') != -1) {
                    start.x = i;
                    start.y = s.indexOf('S');
                }
                if (s.indexOf('K') != -1) {
                    key.x = i;
                    key.y = s.indexOf('K');
                }
                if (s.indexOf('E') != -1) {
                    end.x = i;
                    end.y = s.indexOf('E');
                }
                if (s.indexOf('D') != -1) {
                    men.x = i;
                    men.y = s.indexOf('D');
                }
            }
        }
        int zeroStep = BFS(a, vis, start, end, 'D');
        //System.out.println(zeroStep);
        //System.out.println();
        fillFalse(vis);


        int firstStep = BFS(a, vis, start, key, 'D');
        fillFalse(vis);
        //System.out.println(firstStep);
        int secondStep = BFS(a, vis, key, men, ' ');
        fillFalse(vis);
        //System.out.println(secondStep);
        int thireStep = BFS(a, vis, men, end, ' ');

        //System.out.println(zeroStep + " " + firstStep + " " + secondStep + " " + thireStep);
        int res = firstStep + secondStep + thireStep;
        if (zeroStep != -1 && zeroStep < res) {
            System.out.println(zeroStep);
            return;
        }
        if ((firstStep == -1 || secondStep == -1 || thireStep == -1) && zeroStep == -1) {
            System.out.println(-1);
            return;
        } else
            System.out.println(firstStep + secondStep + thireStep);
        //System.out.println("res:"+firstStep +" " +secondStep+" "+thireStep);

    }

    public static int BFS(char[][] m, boolean[][] vis, Node start, Node end, char c) {
        Queue<Node> q = new LinkedList<>();
        q.offer(new Node(start.x, start.y, 0));
        while (!q.isEmpty()) {
            Node tmp = q.poll();
            //tmp.print();
            vis[tmp.x][tmp.y] = true;
            if (tmp.x == end.x && tmp.y == end.y) {
                return tmp.len;
            }
            for (int i = 0; i < 4; i++) {
                int x = tmp.x + xx[i];
                int y = tmp.y + yy[i];
                if (check(m, vis, x, y, c)) {
                    Node newTmp = new Node(x, y, tmp.len + 1);
                    q.offer(newTmp);
                }
            }

        }
        return -1;
    }

    public static boolean check(char[][] m, boolean[][] vis, int x, int y, char c) {
        if (x < 0 || y < 0 || x > m.length - 1 || y > m[0].length - 1 ||
                m[x][y] == c || vis[x][y] || m[x][y] == 'W') {  //w表示障碍
            return false;
        }
        return true;
    }

    public static void fillFalse(boolean[][] vis) {
        for (int i = 0; i < vis.length; i++) {
            for (int j = 0; j < vis[0].length; j++) {
                vis[i][j] = false;
            }
        }
    }
}

总结:

        1、无障碍,右下走,代价相等 (dp[i][j] = dp[i][j-1] + dp[i-1][j]  或者组合公式)

        变式:有障碍,右下走,代价相等 dp即可

      变式:无障碍,右下走,代价不等 dp即可dp[i][j] = min(dp[i][j-1] + dp[i-1][j]) + a[i][j] 

        变式:无障碍,右下走,代价不等并可能为负值

        题目示例:leetcode 174. 地下城游戏 (反向推)

        

         2、有障碍,任意走,代价相等(大于等于0)(一般性迷宫)

解法很经典:DFS或BFS

        

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 迷宫游戏是一个经典的游戏,玩家需要在迷宫中寻找出口。下面是一个使用Python编写的迷宫游戏源码: ```python import random # 定义迷宫类 class Maze: def __init__(self, rows, cols): self.rows = rows self.cols = cols self.maze = [] self.generate_maze() # 生成迷宫 def generate_maze(self): self.maze = [['#'] * self.cols for _ in range(self.rows)] stack = [(0, 0)] while stack: x, y = stack[-1] self.maze[x][y] = ' ' # 获取随机邻居 neighbors = [] if x > 1 and self.maze[x-2][y] == '#': neighbors.append((x-2, y)) if x < self.rows-2 and self.maze[x+2][y] == '#': neighbors.append((x+2, y)) if y > 1 and self.maze[x][y-2] == '#': neighbors.append((x, y-2)) if y < self.cols-2 and self.maze[x][y+2] == '#': neighbors.append((x, y+2)) if neighbors: nx, ny = random.choice(neighbors) self.maze[(nx+x)//2][(ny+y)//2] = ' ' stack.append((nx, ny)) else: stack.pop() # 打印迷宫 def print_maze(self): for row in self.maze: print(' '.join(row)) # 创建迷宫对象并打印迷宫 maze = Maze(11, 11) maze.print_maze() ``` 此源码使用递归回溯算法生成一个随机迷宫,并通过二维列表来表示迷宫的格子。迷宫的入口是左上角的位置(0, 0),出口位置则是随机生成的。每个方块可以是墙壁(#)或通路(空格),玩家需要通过移动来找到出口。 ### 回答2: 迷宫游戏是一种常见的游戏,在Python中可以使用代码来实现。下面是一个简单的迷宫游戏的Python源码示例: ```python import numpy as np # 迷宫地图 maze = np.array([[1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 0, 0, 0, 1, 1], [1, 0, 0, 0, 1, 0, 1, 1], [1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 0, 0, 0, 1, 0, 1], [1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 1, 1, 1, 1, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1]]) # 设置起点和终点 start = (1, 1) end = (6, 6) # 创建一个空迷宫路径记录 path = np.zeros_like(maze) # 定义一个递归函数来找到路径 def find_path(maze, start, end, path): # 如果当前位置是终点,则找到路径 if start == end: return True # 如果当前位置超出迷宫范围或者是墙壁,则返回False if maze[start] != 0: return False # 标记当前位置已访问 path[start] = 1 # 递归查找四个方向上的路径 if find_path(maze, (start[0]+1, start[1]), end, path) or \ find_path(maze, (start[0]-1, start[1]), end, path) or \ find_path(maze, (start[0], start[1]+1), end, path) or \ find_path(maze, (start[0], start[1]-1), end, path): return True # 如果四个方向上都没有路径,则返回False return False # 查找并打印路径 if find_path(maze, start, end, path): print('找到路径:') print(path) else: print('未找到路径。') ``` 这段代码使用了递归算法来查找迷宫中的路径。迷宫地图使用二维数组表示,其中1表示墙壁,0表示可通过的路径。起点和终点分别指定为`(1, 1)`和`(6, 6)`。使用`find_path`函数来递归查找路径,如果找到路径则返回True,否则返回False。最后,根据查找结果打印相应的信息。 请注意,这只是一个简单的示例代码,实际迷宫游戏可能还包括更复杂的功能,例如计时、计分等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值