📌  相关文章
📜  从二维网格中的给定单元格到达边界单元格的路径,而无需穿过特殊标记的单元格

📅  最后修改于: 2021-10-25 05:15:06             🧑  作者: Mango

给定一个维度为N*M的矩阵,由字符‘M’‘#’‘.’ 组成。并且只有一个‘A’实例。任务是根据以下规则打印从具有值A 的单元格到矩阵的任何边界单元格的任何一条路径:

  • 每一秒,来自单元格“A”的路径可以在所有四个带有“.”的相邻单元格中移动仅字符。字符LRUD 分别代表单元格(X – 1, Y)(X + 1, Y)(X, Y – 1)(X, Y + 1)移动的方向来自单元格(X, Y)
  • 具有字符“#”“M”的单元格是块单元格。
  • 每秒,具有字符‘M’的单元格与字符‘A’同时在所有四个方向上同时传播自身。

注意:如果不存在从A到矩阵的任何边界单元格的任何此类路径,则打印“-1”

例子:

方法:可以通过首先模拟网格上所有块单元‘M’的多源BFS,然后从单元‘A’执行BFS以检查是否可以到达任何边界单元来解决给定的问题。请按照以下步骤解决问题:

  • 初始化一个矩阵,比如G[][] ,它存储到达具有值‘.’的单元格的最小值来自所有具有值‘M’的单元格。
  • 从具有值‘M’ 的所有单元格执行多源 BFS 以找到从具有‘M’ 的最近单元格到达每个单元格的最短时间,并将其存储在矩阵G[][] 中
  • 初始化一个矩阵,比如parent[][]来存储每个单元格的父级,比如(X, Y)当对单元格(X, Y)进行任何移动时。
  • “A”出现的位置开始对网格执行 BFS 遍历,例如(SX, SY)使用以下步骤:
    • 将距离为0的当前单元格(SX,SY)送到队列中。
    • 迭代直到队列不为空并执行以下步骤:
      • 弹出存储在队列中的前单元格。
      • 迭代当前弹出节点的所有有效相邻单元格,并从队列中弹出的单元格中推送具有增加的发现时间的相邻单元格。
      • 在上述步骤中从当前单元格更新移动单元格的父级。
      • 如果相邻单元格是边界单元格,则存储此单元格,例如(EX, EY) ,并跳出循环。
  • 如果未到达矩阵的边界,则打印“-1” 。否则,使用以下步骤打印路径:
    • 迭代直到结束单元格(EX, EY)与起始单元格(SX, SY) 不同
      • 找到结束单元格的父单元格并将单元格(EX, EY)更新为其父单元格。
      • 根据当前结束单元格与其父单元格之间的差异打印方向LRUD

下面是上述方法的一个实现:

C++
// C++ program for tha above approach
#include 
using namespace std;
  
#define largest 10000000
  
// store the grid (2-d grid)
vector > g;
  
// store the coordinates of the 'M' cells
vector > M;
  
// record the parent of a index
vector, int> > > parent;
  
// start indices of A
int sx, sy;
  
// For traversing to adjacent cells
int dx[] = { 1, 0, -1, 0 };
int dy[] = { 0, -1, 0, 1 };
  
// rows, columns, end-x, end-y
int n, m, ex = -1, ey = -1;
  
// function to check if the index
// to be processed is valid or not
bool isvalid(int x, int y)
{
    // should not exceed any of the boundary walls
    if (x < 1 || x > n || y < 0 || y > m)
        return false;
  
    // if current cell has '#'
    if (g[x][y] == largest + 1)
        return false;
  
    return true;
}
  
// function to check if the current
// index is at border ornot
bool isborder(int x, int y)
{
    if (x == 1 || y == 1 || x == n || y == m)
        return true;
  
    return false;
}
  
// function to get the direction when
// movement is made from (x --> ex) and (y --> ey)
char cal(int x, int y, int ex, int ey)
{
    if (x + 1 == ex && y == ey)
        return 'D';
  
    if (x - 1 == ex && y == ey)
        return 'U';
  
    if (x == ex && y + 1 == ey)
        return 'R';
  
    return 'L';
}
  
// Function for the multisource
// bfs on M's to store the timers
void fillMatrix()
{
    // queue to store index
    // for bfs and shortest time
    // for each (i, j)
    queue, int> > q;
    for (auto m : M) {
  
        // time at this moment is passed as zero
        q.push({ m, 0 });
  
        // insert time 0 for this (x, y)
        g[m.first][m.second] = 0;
    }
  
    // process till the queue becomes empty
    while (!q.empty()) {
  
        // get the index and time of
        // the element at front of queue
        int x = q.front().first.first;
        int y = q.front().first.second;
        int time = q.front().second;
  
        // remove it
        q.pop();
  
        // iterate to all the positions
        // from the given position i.e.
        // (x+1, y), (x-1, y), (x, y+1), (x, y-1)
        for (auto i : { 0, 1, 2, 3 }) {
  
            int newx = x + dx[i];
            int newy = y + dy[i];
  
            // check for validity of current index
            if (!isvalid(newx, newy))
                continue;
  
            // not visited before
            if (g[newx][newy] == -1) {
  
                // update time
                g[newx][newy] = (time + 1);
  
                // push it into the queue
                q.push({ { newx, newy }, time + 1 });
            }
        }
    }
  
    // in the end if there are some places on grid
    // that were blocked and BFS couldn't reach there
    // then just manually iterate over them and
    // change them to largest +1 i.e. treat them as '#'
  
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (g[i][j] == -1) {
                g[i][j] = largest;
            }
        }
    }
}
  
// A's BFS. It will return the time
// when A reaches boundary
// if it is not possible, it will return -1
int bfs()
{
    queue, int> > q;
  
    // push the starting (x, y)
    // and it's time as 0
    q.push({ { sx, sy }, 0 });
  
    while (!q.empty()) {
        int x = q.front().first.first;
        int y = q.front().first.second;
        int time = q.front().second;
  
        q.pop();
  
        for (auto i : { 0, 1, 2, 3 }) {
            int newx = x + dx[i];
            int newy = y + dy[i];
  
            if (!isvalid(newx, newy))
                continue;
  
            // Moving to this index is not possible
            if ((time + 1) >= (g[newx][newy]))
                continue;
  
            // index to move on already has
            // a parent i.e. already visited
            if (parent[newx][newy].first.first != -1)
                continue;
  
            // Move to this index and mark the parents
            parent[newx][newy].first.first = x;
            parent[newx][newy].first.second = y;
            parent[newx][newy].second = time + 1;
  
            q.push({ { newx, newy }, time + 1 });
  
            // if this index is a border
            if (isborder(newx, newy)) {
  
                // update ex and ey
                ex = newx;
                ey = newy;
                return time + 1;
            }
        }
    }
  
    // if not possible
    return -1;
}
  
// Function to solve the above problem
void isItPossible(vector > Mat)
{
    // Resize the global vectors
    g.resize(n + 1, vector(m + 1));
    parent.resize(
        n + 1, vector, int> >(m + 1));
  
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
  
            // initialize that no one is currently the
            // parent of (i, j)
            parent[i][j].first.first = -1;
            parent[i][j].first.second = -1;
            parent[i][j].second = -1;
  
            char x = Mat[i - 1][j - 1];
            if (x == 'M') {
                // if the input character is 'M',
                // push the coordinates in M and
                // in the grid take 0 as input
                M.push_back({ i, j });
                g[i][j] = 0;
            }
  
            else if (x == 'A') {
                // this is the start x and start y
  
                sx = i, sy = j;
                g[i][j] = -1;
            }
  
            else if (x == '.')
                g[i][j] = -1;
  
            // denote '#' with largest+1
            else
                g[i][j] = largest + 1;
        }
    }
  
    // if already at the border
    if (isborder(sx, sy)) {
        cout << "Already a boundary cell\n";
        return;
    }
  
    // Multisource bfs
    fillMatrix();
  
    // bfs of A
    int time = bfs();
  
    // if (end x) index is -1 and
    // boundary has not been
    if (ex == -1) {
        cout << ex;
    }
    else {
  
        vector ans; // record the path
  
        while (!(ex == sx && ey == sy)) {
            int x = parent[ex][ey].first.first;
            int y = parent[ex][ey].first.second;
  
            // get the direction of movement
            char dir = cal(x, y, ex, ey);
  
            ans.push_back(dir);
            ex = x;
            ey = y;
        }
  
        reverse(ans.begin(), ans.end());
  
        for (auto x : ans) {
            cout << x;
        }
    }
}
// Driver code
int main()
{
    // Input
    vector > Mat = { { '#', 'M', '.' },
                                  { '#', 'A', 'M' },
                                  { '#', '.', '#' } };
    n = Mat.size();
    m = Mat[0].size();
  
    // Function call
    isItPossible(Mat);
    return 0;
}


输出
D

时间复杂度: O(n*m)
辅助空间: O(n*m)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程