随机迷宫求解

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

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

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

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

代码如下:

class Solution {
    Set<Long> forbid=new HashSet<>();
    long max=(long)1e6;
    long from;
    long to;
    public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
        from=max*(long)source[0]+(long)source[1];
        to=max*(long)target[0]+(long)target[1];
        for(int i=0;i<blocked.length;i++){forbid.add(max*(long)blocked[i][0]+(long)blocked[i][1]);}
        Set<Long> start=new HashSet<>();
        Set<Long> end=new HashSet<>();
        int maxSize=blocked.length*(blocked.length-1)/2;
        findPath(target[0],target[1],maxSize,end);
        findPath(source[0],source[1],maxSize,start);
        return start.size()>maxSize&&end.size()>maxSize||end.contains(from)||start.contains(to);
    }
    public void findPath(int i,int j,int maxSize,Set<Long> set){
        long p=max*(long)i+(long)j;
        if(forbid.contains(p)||set.contains(p)||i<0||j<0||i==max||j==max){return;}
        set.add(p);
        if(set.size()>maxSize||set.contains(to)&&set.contains(from)){return;}
        findPath(i+1,j,maxSize,set);
        findPath(i-1,j,maxSize,set);
        findPath(i,j+1,maxSize,set);
        findPath(i,j-1,maxSize,set);
    }
}

离散化压缩点的坐标,可以大大提高搜索的效率,而且只需要从一个点开始就可以了,不过需要注意的是,每个block点四周的坐标也需要加入离散的map,目的是在保证点的相对位置的同时,使得坐标值本不相邻的点在离散后也是不相邻的 

class Solution {
    boolean cameBefore[][]=new boolean[650][650];
    int r=0;
    int k=0;
    public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
        int max=(int)1e6;
        TreeSet<Integer> row=new TreeSet<>();
        TreeSet<Integer> col=new TreeSet<>();
        row.add(source[0]);
        row.add(target[0]);
        col.add(source[1]);
        col.add(target[1]);
        for(int i=0;i<blocked.length;i++){
            row.add(blocked[i][0]);
            if(blocked[i][0]>0){row.add(blocked[i][0]-1);}
            if(blocked[i][0]<max-1){row.add(blocked[i][0]+1);}
            col.add(blocked[i][1]);
            if(blocked[i][1]>0){col.add(blocked[i][1]-1);}
            if(blocked[i][1]<max-1){col.add(blocked[i][1]+1);}
        }
        Map<Integer,Integer> map1=new HashMap<>();//行映射
        Map<Integer,Integer> map2=new HashMap<>();//列映射
        for(int a:row){
            map1.put(a,r);
            r++;
        }
        for(int a:col){
            map2.put(a,k);
            k++;
        }
        for(int i=0;i<blocked.length;i++){cameBefore[map1.get(blocked[i][0])][map2.get(blocked[i][1])]=true;}
        findPath(map1.get(source[0]),map2.get(source[1]));
        return cameBefore[map1.get(target[0])][map2.get(target[1])];
    }
    public void findPath(int x,int y){
        if(x<0||y<0||x==r||y==k||cameBefore[x][y]){return;}
        cameBefore[x][y]=true;
        findPath(x+1,y);
        findPath(x-1,y);
        findPath(x,y+1);
        findPath(x,y-1);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值