📜  在地雷路径中找到最短的安全路线

📅  最后修改于: 2021-05-24 19:21:21             🧑  作者: Mango

给定矩形矩阵形式的路径,该路径具有任意放置的少量地雷(标记为0),请计算从矩阵第一列中的任何单元到矩阵最后列中的任何单元的最短安全路径的长度。我们必须避免地雷及其附近的四个牢房(左,右,上方和下方),因为它们也不安全。我们只能移到不是地雷的相邻牢房。也就是说,路线不能包含任何对角线移动。

例子:

Input: 
A 12 x 10 matrix with landmines marked as 0

[ 1  1  1  1  1  1  1  1  1  1 ]
[ 1  0  1  1  1  1  1  1  1  1 ]
[ 1  1  1  0  1  1  1  1  1  1 ]
[ 1  1  1  1  0  1  1  1  1  1 ]
[ 1  1  1  1  1  1  1  1  1  1 ]
[ 1  1  1  1  1  0  1  1  1  1 ]
[ 1  0  1  1  1  1  1  1  0  1 ]
[ 1  1  1  1  1  1  1  1  1  1 ]
[ 1  1  1  1  1  1  1  1  1  1 ]
[ 0  1  1  1  1  0  1  1  1  1 ]
[ 1  1  1  1  1  1  1  1  1  1 ]
[ 1  1  1  0  1  1  1  1  1  1 ]

Output:  
Length of shortest safe route is 13 (Highlighted in Bold)

这个想法是使用回溯。我们首先将地雷的所有相邻单元标记为不安全。然后,对于矩阵第一列的每个安全单元,我们在所有允许的方向上前进,并递归检查它们是否通向目的地。如果找到了目标,则我们将更新最短路径的值,否则,如果以上解决方案均无效,我们将从函数返回false。

以下是上述想法的实现–

C++
// C++ program to find shortest safe Route in
// the matrix with landmines
#include 
using namespace std;
#define R 12
#define C 10
 
// These arrays are used to get row and column
// numbers of 4 neighbours of a given cell
int rowNum[] = { -1, 0, 0, 1 };
int colNum[] = { 0, -1, 1, 0 };
 
// A function to check if a given cell (x, y)
// can be visited or not
bool isSafe(int mat[R][C], int visited[R][C],
            int x, int y)
{
    if (mat[x][y] == 0 || visited[x][y])
        return false;
 
    return true;
}
 
// A function to check if a given cell (x, y) is
// a valid cell or not
bool isValid(int x, int y)
{
    if (x < R && y < C && x >= 0 && y >= 0)
        return true;
 
    return false;
}
 
// A function to mark all adjacent cells of
// landmines as unsafe. Landmines are shown with
// number 0
void markUnsafeCells(int mat[R][C])
{
    for (int i = 0; i < R; i++)
    {
        for (int j = 0; j < C; j++)
        {
            // if a landmines is found
            if (mat[i][j] == 0)
            {
              // mark all adjacent cells
              for (int k = 0; k < 4; k++)
                if (isValid(i + rowNum[k], j + colNum[k]))
                    mat[i + rowNum[k]][j + colNum[k]] = -1;
            }
        }
    }
 
    // mark all found adjacent cells as unsafe
    for (int i = 0; i < R; i++)
    {
        for (int j = 0; j < C; j++)
        {
            if (mat[i][j] == -1)
                mat[i][j] = 0;
        }
    }
 
    // Uncomment below lines to print the path
    /*for (int i = 0; i < R; i++)
    {
        for (int j = 0; j < C; j++)
        {
            cout << std::setw(3) << mat[i][j];
        }
        cout << endl;
    }*/
}
 
// Function to find shortest safe Route in the
// matrix with landmines
// mat[][] - binary input matrix with safe cells marked as 1
// visited[][] - store info about cells already visited in
// current route
// (i, j) are cordinates of the current cell
// min_dist --> stores minimum cost of shortest path so far
// dist --> stores current path cost
void findShortestPathUtil(int mat[R][C], int visited[R][C],
                          int i, int j, int &min_dist, int dist)
{
    // if destination is reached
    if (j == C-1)
    {
        // update shortest path found so far
        min_dist = min(dist, min_dist);
        return;
    }
 
    // if current path cost exceeds minimum so far
    if (dist > min_dist)
        return;
 
    // include (i, j) in current path
    visited[i][j] = 1;
 
    // Recurse for all safe adjacent neighbours
    for (int k = 0; k < 4; k++)
    {
        if (isValid(i + rowNum[k], j + colNum[k]) &&
            isSafe(mat, visited, i + rowNum[k], j + colNum[k]))
        {
            findShortestPathUtil(mat, visited, i + rowNum[k],
                           j + colNum[k], min_dist, dist + 1);
        }
    }
 
    // Backtrack
    visited[i][j] = 0;
}
 
// A wrapper function over findshortestPathUtil()
void findShortestPath(int mat[R][C])
{
    // stores minimum cost of shortest path so far
    int min_dist = INT_MAX;
 
    // create a boolean matrix to store info about
    // cells already visited in current route
    int visited[R][C];
 
    // mark adjacent cells of landmines as unsafe
    markUnsafeCells(mat);
 
    // start from first column and take minimum
    for (int i = 0; i < R; i++)
    {
        // if path is safe from current cell
        if (mat[i][0] == 1)
        {
            // initailize visited to false
            memset(visited, 0, sizeof visited);
 
            // find shortest route from (i, 0) to any
            // cell of last column (x, C - 1) where
            // 0 <= x < R
            findShortestPathUtil(mat, visited, i, 0,
                                 min_dist, 0);
 
            // if min distance is already found
            if(min_dist == C - 1)
                break;
        }
    }
 
    // if destination can be reached
    if (min_dist != INT_MAX)
        cout << "Length of shortest safe route is "
             << min_dist;
 
    else // if the destination is not reachable
        cout << "Destination not reachable from "
             << "given source";
}
 
// Driver code
int main()
{
    // input matrix with landmines shown with number 0
    int mat[R][C] =
    {
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
        { 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 }
    };
 
    // find shortest path
    findShortestPath(mat);
 
    return 0;
}


Java
// Java program to find shortest safe Route
// in the matrix with landmines
import java.util.Arrays;
 
class GFG{
 
static final int R = 12;
static final int C = 10;
 
// These arrays are used to get row and column
// numbers of 4 neighbours of a given cell
static int rowNum[] = { -1, 0, 0, 1 };
static int colNum[] = { 0, -1, 1, 0 };
 
static int min_dist;
 
// A function to check if a given cell (x, y)
// can be visited or not
static boolean isSafe(int[][] mat, boolean[][] visited,
                      int x, int y)
{
    if (mat[x][y] == 0 || visited[x][y])
        return false;
 
    return true;
}
 
// A function to check if a given cell (x, y) is
// a valid cell or not
static boolean isValid(int x, int y)
{
    if (x < R && y < C && x >= 0 && y >= 0)
        return true;
 
    return false;
}
 
// A function to mark all adjacent cells of
// landmines as unsafe. Landmines are shown with
// number 0
static void markUnsafeCells(int[][] mat)
{
    for(int i = 0; i < R; i++)
    {
        for(int j = 0; j < C; j++)
        {
             
            // If a landmines is found
            if (mat[i][j] == 0)
            {
                 
                // Mark all adjacent cells
                for(int k = 0; k < 4; k++)
                    if (isValid(i + rowNum[k], j + colNum[k]))
                        mat[i + rowNum[k]][j + colNum[k]] = -1;
            }
        }
    }
 
    // Mark all found adjacent cells as unsafe
    for(int i = 0; i < R; i++)
    {
        for(int j = 0; j < C; j++)
        {
            if (mat[i][j] == -1)
                mat[i][j] = 0;
        }
    }
 
    // Uncomment below lines to print the path
    /*
     * for (int i = 0; i < R; i++) {
     * for (int j = 0; j < C; j++) { cout <<
     * std::setw(3) << mat[i][j]; } cout << endl; }
     */
}
 
// Function to find shortest safe Route in the
// matrix with landmines
// mat[][] - binary input matrix with safe cells marked as 1
// visited[][] - store info about cells already visited in
// current route
// (i, j) are cordinates of the current cell
// min_dist --> stores minimum cost of shortest path so far
// dist --> stores current path cost
static void findShortestPathUtil(int[][] mat,
                                 boolean[][] visited,
                                 int i, int j, int dist)
{
     
    // If destination is reached
    if (j == C - 1)
    {
         
        // Update shortest path found so far
        min_dist = Math.min(dist, min_dist);
        return;
    }
     
    // If current path cost exceeds minimum so far
    if (dist > min_dist)
        return;
 
    // include (i, j) in current path
    visited[i][j] = true;
 
    // Recurse for all safe adjacent neighbours
    for(int k = 0; k < 4; k++)
    {
        if (isValid(i + rowNum[k], j + colNum[k]) &&
            isSafe(mat, visited, i + rowNum[k],
                                 j + colNum[k]))
        {
            findShortestPathUtil(mat, visited, i + rowNum[k],
                             j + colNum[k], dist + 1);
        }
    }
 
    // Backtrack
    visited[i][j] = false;
}
 
// A wrapper function over findshortestPathUtil()
static void findShortestPath(int[][] mat)
{
     
    // Stores minimum cost of shortest path so far
    min_dist = Integer.MAX_VALUE;
     
    // Create a boolean matrix to store info about
    // cells already visited in current route
    boolean[][] visited = new boolean[R][C];
 
    // Mark adjacent cells of landmines as unsafe
    markUnsafeCells(mat);
 
    // Start from first column and take minimum
    for(int i = 0; i < R; i++)
    {
         
        // If path is safe from current cell
        if (mat[i][0] == 1)
        {
             
            // Initailize visited to false
            for(int k = 0; k < R; k++)
            {
                Arrays.fill(visited[k], false);
            }
 
            // Find shortest route from (i, 0) to any
            // cell of last column (x, C - 1) where
            // 0 <= x < R
            findShortestPathUtil(mat, visited, i, 0, 0);
 
            // If min distance is already found
            if (min_dist == C - 1)
                break;
        }
    }
     
    // If destination can be reached
    if (min_dist != Integer.MAX_VALUE)
        System.out.println("Length of shortest " +
                           "safe route is " + min_dist);
 
    else
     
        // If the destination is not reachable
        System.out.println("Destination not " +
                           "reachable from given source");
}
 
// Driver code
public static void main(String[] args)
{
     
    // Input matrix with landmines shown with number 0
    int[][] mat = {
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
        { 1, 0, 1, 1, 1, 1, 1, 1, 0, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 },
        { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
        { 1, 1, 1, 0, 1, 1, 1, 1, 1, 1 } };
 
    // Find shortest path
    findShortestPath(mat);
}
}
 
// This code is contributed by sanjeev2552


C++
// C++ program to find shortest safe Route in
// the matrix with landmines
#include 
using namespace std;
 
#define R 12
#define C 10
 
struct Key{
    int x,y;
    Key(int i,int j){ x=i;y=j;};
};
 
// These arrays are used to get row and column
// numbers of 4 neighbours of a given cell
int rowNum[] = { -1, 0, 0, 1 };
int colNum[] = { 0, -1, 1, 0 };
 
// A function to check if a given cell (x, y) is
// a valid cell or not
bool isValid(int x, int y)
{
    if (x < R && y < C && x >= 0 && y >= 0)
        return true;
 
    return false;
}
 
// A function to mark all adjacent cells of
// landmines as unsafe. Landmines are shown with
// number 0
void findShortestPath(int mat[R][C]){
    int i,j;
 
    for (i = 0; i < R; i++)
    {
        for (j = 0; j < C; j++)
        {
            // if a landmines is found
            if (mat[i][j] == 0)
            {
            // mark all adjacent cells
            for (int k = 0; k < 4; k++)
                if (isValid(i + rowNum[k], j + colNum[k]))
                    mat[i + rowNum[k]][j + colNum[k]] = -1;
            }
        }
    }
// mark all found adjacent cells as unsafe
    for (i = 0; i < R; i++)
    {
        for (j = 0; j < C; j++)
        {
            if (mat[i][j] == -1)
                mat[i][j] = 0;
        }
    }
 
    int dist[R][C];
 
    for(i=0;i q;
 
    for(i=0;i


输出:

Length of shortest safe route is 13

另一种方法:可以借助“广度优先搜索”在多项式时间内求解。将具有1值的单元格放入距离为0的队列中。随着BFS进行,将计算从第一列到每个单元格的最短路径。最后,对于最后一列中的可到达单元格,输出最小距离。

C++中的实现如下:

C++

// C++ program to find shortest safe Route in
// the matrix with landmines
#include 
using namespace std;
 
#define R 12
#define C 10
 
struct Key{
    int x,y;
    Key(int i,int j){ x=i;y=j;};
};
 
// These arrays are used to get row and column
// numbers of 4 neighbours of a given cell
int rowNum[] = { -1, 0, 0, 1 };
int colNum[] = { 0, -1, 1, 0 };
 
// A function to check if a given cell (x, y) is
// a valid cell or not
bool isValid(int x, int y)
{
    if (x < R && y < C && x >= 0 && y >= 0)
        return true;
 
    return false;
}
 
// A function to mark all adjacent cells of
// landmines as unsafe. Landmines are shown with
// number 0
void findShortestPath(int mat[R][C]){
    int i,j;
 
    for (i = 0; i < R; i++)
    {
        for (j = 0; j < C; j++)
        {
            // if a landmines is found
            if (mat[i][j] == 0)
            {
            // mark all adjacent cells
            for (int k = 0; k < 4; k++)
                if (isValid(i + rowNum[k], j + colNum[k]))
                    mat[i + rowNum[k]][j + colNum[k]] = -1;
            }
        }
    }
// mark all found adjacent cells as unsafe
    for (i = 0; i < R; i++)
    {
        for (j = 0; j < C; j++)
        {
            if (mat[i][j] == -1)
                mat[i][j] = 0;
        }
    }
 
    int dist[R][C];
 
    for(i=0;i q;
 
    for(i=0;i

输出:

Length of shortest safe route is 13