leetcode1036 逃离大迷宫(bfs 坐标hash处理)

链接:https://leetcode-cn.com/problems/escape-a-large-maze/

题目

在一个 106 x 106 的网格中,每个网格上方格的坐标为 (x, y) 。

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

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

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

用例

示例 1:

输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
输出:false
解释:
从源方格无法到达目标方格,因为我们无法在网格中移动。
无法向北或者向东移动是因为方格禁止通行。
无法向南或者向西移动是因为不能走出网格。
示例 2:

输入:blocked = [], source = [0,0], target = [999999,999999]
输出:true
解释:
因为没有方格被封锁,所以一定可以到达目标方格。

提示:

0 <= blocked.length <= 200
blocked[i].length == 2
0 <= xi, yi < 106
source.length == target.length == 2
0 <= sx, sy, tx, ty < 106
source != target
题目数据保证 source 和 target 不在封锁列表内

思路

由于网格数量为106*106,所以直接dfs或者bfs都会超时
但是blocked封锁点数量最多只有200个,也就是说source点以及target点附近能走的点数大于blocked能封锁的最大面积点数 或者在能走的范围内直接搜到对方,即为可以达到
blocked的最大封锁面积 如图即为和边界围成三角的情况,封锁面积为(n-1)*n/2,所以问题转化为 对source点 和target点bfs搜索 判断可行路径大于最大封锁点的问题
坐标hash构造可以由两种:

  1. 使用一个素数作为底,比如13331 ,131等 x*base+y作为hash值
  2. 使用大数二进制存储 因为是106*106,220-1大于106,所以可以用大数二进制来存坐标 ,取其中40位 前20位存x,后20位存y 即(x<<20+y)
class Solution {
public:
    static constexpr int dir[4][2]={{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    long long BASE=13331 ;
    int MAX=1e5;
    static constexpr int edge=1e6;
    unordered_set<long long>st;
    bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
        for(auto &b:blocked){
            st.insert(b[0]*BASE +b[1]);
        }
        int n=blocked.size();
        MAX=(n-1)*n/2;
        return check(source,target)&check(target,source);
    }
    bool check(vector<int >&a,vector<int>&b){
        unordered_set<long long>vis;
        queue<pair<int,int>>q;
        q.push({a[0],a[1]});
        vis.insert(a[0]*BASE+a[1]);
        while(q.size() &&vis.size()<=MAX){
            auto t=q.front();
            q.pop();
            int x=t.first,y=t.second;
            if(x==b[0]&&y==b[1])
                return true;
            for(int i=0;i<4;i++){
                int nx=x+dir[i][0],ny=y+dir[i][1];
                if(nx<0||nx>edge-1||ny<0||ny>edge-1)continue;
                if(st.count(nx*BASE+ny))continue;//是阻碍点则跳过
                if(vis.count(nx*BASE+ny))continue;
                q.push({nx,ny});
                vis.insert(nx*BASE+ny);
            }
        }
        return vis.size()>MAX;// 注意判断的是走过路径的数量

    }
};
posted @ 2022-01-11 14:59  kitamu  阅读(172)  评论(0编辑  收藏  举报
Live2D