简体   繁体   English

找到最短路径的算法,有障碍物

[英]Algorithm to find the shortest path, with obstacles

I have a collection of Points which represents a grid, I'm looking for an algorithm that gets me the shortest distance between point A and B. The catch being any point (excluding A and B) can have an obstacle obstructing the path, and thus must be detoured. 我有一个代表网格的点集合,我正在寻找一个能让我获得A点和B点之间最短距离的算法。任何点(不包括A和B)的捕获都会有阻碍路径的障碍,并且因此必须绕道而行。 The path may not move in diagonals. 路径可能不会以对角线移动。

For anyone else looking to solve this type of problem, I found these references to be very useful: 对于任何想要解决此类问题的人,我发现这些引用非常有用:

http://optlab-server.sce.carleton.ca/POAnimations2007/DijkstrasAlgo.html http://optlab-server.sce.carleton.ca/POAnimations2007/DijkstrasAlgo.html

http://en.literateprograms.org/Dijkstra%27s_algorithm_%28Java%29#chunk%20def:visit%20each%20vertex%20u,%20always%20visiting%20vertex%20with%20smallest%20minDistance%20first http://en.literateprograms.org/Dijkstra%27s_algorithm_%28Java%29#chunk%20def:visit%20each%20vertex%20u,%20always%20visiting%20vertex%20with%20smallest%20minDistance%20first

This is an excellent spot to use the A* search algorithm , a heuristic search algorithm that finds optimal paths between points very quickly even when there are obstacles present. 这是使用A *搜索算法的绝佳场所, A *搜索算法是一种启发式搜索算法,即使存在障碍物,也能非常快速地找到点之间的最佳路径。 The idea is to convert the grid into a graph where each cell in the grid is a node and in which there is an edge between any two adjacent cells that aren't obstructed from one another. 该想法是将网格转换为图形 ,其中网格中的每个单元是节点,并且在任何两个相邻单元之间存在不相互阻碍的边缘。 Once you have this graph, the answer you're looking for is the shortest path in the graph from the start node to the destination node. 获得此图表后,您要查找的答案是图表中从起始节点到目标节点的最短路径。

In order to use A*, you'll need a heuristic function that "guesses" the distance from any point on the grid to the destination square. 为了使用A *,您需要一个启发式功能,“猜测”从网格上的任何点到目标方块的距离。 One good heuristic for this would be to use the Manhattan distance between the two points. 一个很好的启发式方法是使用两点之间的曼哈顿距离

If you're looking for an easier but still extremely efficient algorithm for finding the shortest path, consider looking into Dijkstra's algorithm , which can be thought of as a simpler version of A*. 如果您正在寻找一种更简单但仍然非常有效的查找最短路径的算法 ,请考虑查看Dijkstra的算法 ,该算法可以被认为是A *的更简单版本。 It's a bit slower than A*, but still runs extremely quickly and guarantees an optimal answer. 它比A *慢一点,但仍能非常快速地运行并保证最佳答案。

Hope this helps! 希望这可以帮助!

This is a simple problem that can be solved using Breadth First Search 这是一个可以使用广度优先搜索解决的简单问题

 /**
  * computing distance of each cell from the starting cell 
  * avoiding obstacles, 0 represents obstacle 1 represents non obstacle
  * we can take only one step x-1;x+1;y-1;y+1
 */

#include<iostream>
#include<queue>
#include<stdio.h>
using namespace std;

class XY
{
 public :
 int x;
int y;
};

int main()
{
int grid[8][8] = {
    {1,1,1,1,1,1,1,1},
    {1,0,0,0,1,1,1,1},
    {1,1,0,0,1,1,1,1},
    {1,1,0,0,1,1,1,1},
    {1,1,1,2,0,1,0,0},
    {1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1},
    {1,1,1,1,1,1,1,1}
};


int rows = 8;
int cols = 8;

int distance[rows][cols];

for(int m = 0;m<rows;m++)
{
    for(int n =0;n<cols;n++)
    {
        distance[m][n] = -1;
    }
}

queue<XY> iterator;


XY xy;
xy.x = 0;
xy.y = 0;
distance[0][0] = 0;
iterator.push(xy);

while(!iterator.empty())
{
    xy = iterator.front();
    iterator.pop();
    //printf("popped %d+%d\n",xy.x ,xy.y);
    for(int p = -1;p<2;p++)
    {
        for(int q = -1;q<2;q++)
        {
            if(p == q)continue;
            int i = xy.x + p;
            int j = xy.y + q;

            if(i<0)i=0;
            if(j<0)j=0;
            if(i>rows-1)i=rows-1;
            if(j>cols-1)j=cols-1;

            if(i== xy.x && j == xy.y)continue;

    //              printf("i,j = %d,%d\n",i,j);

            if(distance[i][j] == -1)
            {
     //                 printf("******\n");
                if(grid[i][j] != 0)
                {
     //                 printf("assigned distance %d to %d+%d\n",distance[xy.x][xy.y] + 1,i,i); 
                distance[i][j] = distance[xy.x][xy.y] + 1;
                XY xyn;
                xyn.x = i;
                xyn.y = j;  
                iterator.push(xyn);
      //                    printf("pushed %d+%d\n",xyn.x,xyn.y);
                }
            }

        }
    }
}

for(int x = 0;x<rows;x++)
{
    for(int y =0;y<cols;y++)
    {
        printf("%d ",distance[x][y]);   
    }
    printf("\n");
}
return 0;
}

I believe that the given problem can be solved by Breadth First Search(BFS) as mentioned earlier. 我相信如前所述,广度优先搜索(BFS)可以解决给定的问题。 Establishing a problem statement is important. 建立问题陈述很重要。 So let's describe the problem and then we move to the solution part of it. 因此,让我们描述问题,然后我们转向解决方案的一部分。

Problem Description: 问题描述:

You are in charge of preparing a recently purchased lot for one of a new building. 您负责为新建筑物之一准备最近购买的地块。 The lot is covered with trenches and has a single obstacle that needs to be taken down before the foundation can be prepared for the building. 该地块覆盖着沟渠,并且在为建筑物准备地基之前需要拆除一个障碍物。 The demolition robot must remove the obstacle before progress can be made on the building. 拆除机器人必须移除障碍物才能在建筑物上进行。 Write an algorithm to determine the minimum distance required for the demolition robot to remove the obstacle. 编写算法以确定拆除机器人移除障碍物所需的最小距离。

Assumptions: 假设:

  1. The lot is flat, except for trenches, and can be represented as a 2-D grid. 除了沟槽之外,该地块是扁平的,并且可以表示为二维网格。
  2. The demolition robot must start from the top left corner of the lot, which is always flat and can move one block up, down, right or left at a time. 拆除机器人必须从地段的左上角开始,该地块始终是平坦的,并且可以一次向上,向下,向右或向左移动一个街区。
  3. The demolition robot cannot enter trenches and cannot leave the lot. 拆迁机器人不能进入战壕,不能离开地段。
  4. The flat areas are represented as 1, areas with trenches as 0 and obstacle by 9. 平坦区域表示为1,区域的沟槽为0,障碍为9。

Output: 输出:

Return an integer representing the minimum distance traversed to remove the obstacle else return -1. 返回一个整数,表示移动的最小距离以移除障碍物,否则返回-1。

Solution

from collections import defaultdict

from collections import deque


def is_valid(i, j, m, n, matrix, visited):
    if i >= 0 and j >= 0 \
            and i < m and j < n \
            and visited[i][j] is False \
            and matrix[i][j] in (1, 9):
        return True

    return False


def remove_obstacle(matrix, m, n):
    queue = deque()
    i = 0
    j = 0
    queue.append((i, j, 0))

    visited = [[False for _ in range(n)] for _ in range(m)]
    distance_matrix = [[100 for _ in range(n)] for _ in range(m)]

    visited[i][j] = True

    while queue:
        i, j, distance = queue.popleft()
        distance_matrix[i][j] = distance

        visited[i][j] = True

        if matrix[i][j] == 9:
            return distance
        new_distance = distance + 1
        if is_valid(i + 1, j, m, n, matrix, visited):
            queue.append((i + 1, j, new_distance))

        if is_valid(i - 1, j, m, n, matrix, visited):
            queue.append((i - 1, j, new_distance))

        if is_valid(i, j + 1, m, n, matrix, visited):
            queue.append((i, j + 1, new_distance))

        if is_valid(i, j - 1, m, n, matrix, visited):
            queue.append((i, j - 1, new_distance))

    return -1


if __name__ == '__main__':
    m = 5
    n = 4
    l = [
        [1, 1, 1, 1],
        [0, 1, 1, 1],
        [0, 1, 0, 1],
        [1, 1, 9, 1],
        [0, 0, 1, 1]
    ]

    bfs = remove_obstacle(l, m, n)
    assert bfs == 5

    m = 3
    n = 3
    l = [
        [1, 0, 0],
        [1, 0, 0],
        [1, 9, 1]
    ]

    bfs = remove_obstacle(l, m, n)
    assert bfs == 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM