【每日一题】带限制的DFS——逃离大迷宫,今天开始恢复更新

1036. 逃 离 大 迷 宫 \color{red}{1036. 逃离大迷宫} 1036.

在一个 10^6 x 10^6 的网格中,每个网格上方格的坐标为 (x, y)

现在从源方格 source = [sx, sy] 开始出发,意图赶往目标方格 target = [tx, ty] 。数组 blocked 是封锁的方格列表,其中每个 blocked[i] = [xi, yi] 表示坐标为 (xi, yi) 的方格是禁止通行的。

每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 在给出的封锁列表 blocked 上。同时,不允许走出网格。

只有在可以通过一系列的移动从源方格 source 到达目标方格 target 时才返回 true。否则,返回 false

数据(关键)约束:

  • 0 <= blocked.length <= 200

解题思路:

  1. 首先对于这种网格中找路径的问题,一般都是通过搜索算法解题——根据是否要求最短路径,数据量大小等酌情选取DFS或者BFS,以及其他更优的搜索算法…
  2. 由于这道题的数据量,而且没有要求找一条最短的“逃脱”路径,如果通过BFS逐步扩展的话肯定没机会的;考虑一下DFS,在根据这道题的Hard难度,不难想到使用优化后的DFS算法——最常见的优化就是剪枝优化了(常用剪枝策略有三种:记忆化-相同值从记忆数组中提取结果、最优解判断-如果当前枝差于当前最优剪枝、可行性剪枝-当前枝不可能获得解剪枝)
  3. 但是这道题应该不是剪枝,而属于距离限制的DFS搜索:由于一个特殊的数据约束,封锁格子最多只有200格,假设这些格子按照斜线排序达到最好封锁效果,类似与如下边,只要DFS到达的点和原点的曼哈顿距离到达一定范围,即肯定冲破封锁。这个范围根据最好的封锁效果(图1)不难得到为blocked.length
  4. 于是,在DFS达到据原点一定距离的点,或者直接搜索到目标,即表示该节点“free”了

解题代码:

还有很大改进空间:

class Solution {
    
    
    //封锁格子数量
    int len;
    //上下左右方向数组
    int[][] d;
    //保存访问信息
    Map<Integer,Set<Integer>> v;
    //全局block
    int[][] b;

    public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
    
    
        b=blocked;
        len=blocked.length;
        d=new int[][]{
    
    {
    
    -1,0},{
    
    1,0},{
    
    0,-1},{
    
    0,1}};

        //访问原节点
        v=new HashMap<>();
        Set<Integer> sou=new HashSet<Integer>();
        sou.add(source[1]);
        v.put(source[0],sou);

        //判断原节点是否free
        if(dfs(source,source,target)){
    
    
            
            
            v=new HashMap<>();
            Set<Integer> tar=new HashSet<Integer>();
            tar.add(target[1]);
            v.put(target[0],tar);

            //判断目标节点是否free
            if(dfs(target,target,source))
                return true;
        }

        return false;
    }

    public boolean dfs(int[] cur,int[] o,int[] t){
    
    
        //如果超过范围,或者到达目标返回true
        if((Math.abs(cur[0]-o[0])+Math.abs(cur[1]-o[1]))>=len||(cur[0]==t[0]&&cur[1]==t[1])){
    
    
            return true;
        }
        else{
    
    
            for(int i=0;i<4;i++){
    
    
                int mx=cur[0]+d[i][0];
                int my=cur[1]+d[i][1];
                if(mx<0||mx>=1000000||my<0||my>=1000000||judge(mx,my)){
    
    
                    continue;
                }
                else{
    
    
                    Set<Integer> j=v.get(mx);
                    if(j==null||!j.contains(my)){
    
    
                        if(j==null){
    
    
                            j=new HashSet<Integer>();
                        }
                        j.add(my);
                        v.put(mx,j);
                        if(dfs(new int[]{
    
    mx,my},o,t))
                            return true;
                    }
                    else{
    
    
                        continue;
                    }
                }
            }
        }
        return false;
    }

    //判断是否是blocked
    public boolean judge(int x,int y){
    
    
        for(int i=0;i<len;i++){
    
    
            if(b[i][0]==x&&b[i][1]==y)
                return true;
        }
        return false;
    }

}

结尾

题目来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems

⭐️关注作者,带你刷题,从简单的算法题了解最常用的算法技能(寒假每日一题)
⭐️关注作者刷题——简单到进阶,让你不知不觉成为无情的刷题机器,有问题请私信

猜你喜欢

转载自blog.csdn.net/caqjeryy/article/details/123507430