迷宫问题总结(算法)

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
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值