【算法】机器人走迷宫破壁解法(适用于走迷宫、最短路径算法)-20200412

标题:机器人走迷宫破壁解法(适用于走迷宫、最短路径算法)-20200412
问题描述:

  1. 一块矩形方格,含有障碍和可通行格子,求从某一点到另外一点的最短距离?N*M的矩阵;
    其中,1代表障碍,0代表可通行;示例:给定二维矩阵
    0 0 1 0
    0 1 0 0
    0 0 0 0
    0 0 0 0

出发点坐标[0, 0],终点坐标[0, 3];
假如最多有一次破障碍格子的机会,java编写int solve(int[][] grids, int[] start, int[] end)返回最短距离;BFS

思路:
(1)当然可用dfs深度优先遍历;但是,有没有BFS呢?
dfs的特点:找到每条完整路径再返回,不到黄河心不死;
bfs:尽量扩散,看是否能走到终点;
(2)考虑BFS,每次按层遍历,在破壁和不破壁的情况下,最远可以走多远;已经破壁则不能再破壁了;
(3)那么有人问?到底何时破壁呢?尽早破壁,尽快扩散;基于扩散的点再次扩散;尽早到达最远;
例如:
0 0 1 0
0 1 0 0
0 0 0 0
0 0 0 0
第一层壁不破,更待何时?破除四周的障碍,谁最早到达外层,谁就获胜。因为各自距离是相等的,是无权图。
第一步:[0, 0]的下一层点集:[0, 1],[1, 0];这是在破壁和不破壁达到的最远点;
第二步:基于[0, 1],[1, 0],最多可以扩散哪些点?同样,找破壁和不破壁到达节点的并集;已经访问过的就不要再访问了。
[0, 1]可以访问的点:破壁的才能访问,同时记录状态:已经破壁一次。[0, 2],[1, 1];
[1, 0]可以访问的[2,0];不破壁的情况下可以访问。
并集:[0, 2],[1, 1],[2,0];前两个是破壁一次访问的,后一个是非破壁访问的。
第三步:
[0, 2]可达[0, 3];其实就是终点,直接可达return;
[1, 1],[2,0]:不用看了;
下面看bfs解法;

dfs思路:
(1)[0, 0]到[0, 3]的距离最短,[0,0]等价于相邻点[0, 1],[1, 0]分别到终点的距离最小值,再加上邻近的1;对于是否破壁求分支;
dfs([0,0],[0,3])等价于:
min(dfs([0,1],[0,3],破壁),dfs([0,1],[0,3],未用破壁), dfs([1,0],[0,3],破壁),dfs([1,0],[0,3],未破壁));
不需要破壁时就不用;考虑破壁与否和四个方向求最小值;遍历次数太多;

更复杂场景,若给多次机会,如何解呢?亦是尽早破壁,走得最远;

package robot;

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

public class SolutionUpdate {
int[][] direct = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

// 方格的bfs;
public int bfs(int[][] grids, int[] start, int[] end) {
    // 写是否已经访问的状态;
    int[][] state = new int[grids.length][grids[0].length];
    Queue queue = new LinkedList();
    // 入队时标记是否破壁。0:未使用;1:已使用;
    state[start[0]][start[1]] = 1;
    queue.offer(new int[]{start[0], start[1], 0});
    int count = 0;
    while (!queue.isEmpty()) {
        // 扩散开始
        count++;
        // 每次要把扩散一次的节点全部拿出来,才能进行下一步扩散;
        System.out.println("queue size is:" + queue.size());
        int size = queue.size();
        for (int inx = 0; inx < size; inx++) {
            int[] node = (int[]) queue.poll();
            // 当扩散到终点就拉出来;注意:若要打印最短路径,到达终点时可以拉出来;
            if (node[0] == end[0] && node[1] == end[1]) {
                // 起点塞进来已经加1,故要减去;
                return count - 1;
            }
            for (int[] item : direct) {
                int nextX = node[0] + item[0];
                int nextY = node[1] + item[1];
                if (nextX >= 0 && nextX <= grids.length - 1
                        && nextY >= 0 && nextY <= grids[0].length - 1
                        && state[nextX][nextY] != 1) {
                    System.out.println("queue size: " + queue.size()+"--;" +node[0] + "," + node[1] + ";" + "--:" + nextX + "," + nextY + "");
                    if (node[2] == 0 && grids[nextX][nextY] == 0) {
                        // 不用破壁
                        queue.offer(new int[]{nextX, nextY, 0});
                        state[nextX][nextY] = 1;
                    } else if (node[2] == 0 && grids[nextX][nextY] == 1) {
                        // 使用破壁
                        queue.offer(new int[]{nextX, nextY, 1});
                        state[nextX][nextY] = 1;
                    } else if (node[2] == 1 && grids[nextX][nextY] == 0) {
                        // 不能再使用破壁;乖乖地按常理走吧。
                        queue.offer(new int[]{nextX, nextY, 0});
                        state[nextX][nextY] = 1;
                    } else {
                        // node[2] == 1 && grids[nextX][nextY] == 1
                        // 不能走
                        state[nextX][nextY] = 1;
                    }
                }
            }
        }
        System.out.println("----------");
    }
    return -1;
}

}

测试类:
int[][] grids = {
{0, 0, 1, 0},
{0, 1, 0, 0},
{0, 0, 0, 0},
{0, 0, 0, 0}
};
int[] start = {0, 0};
int[] end = {0, 3};
结果:
3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值