Solve the Maze
Explicación
La observación principal es que si hay una persona mala junto a una persona buena, entonces es imposible. Por ejemplo, consideremos lo siguiente:
#####
##BG#
###..
####.Como la persona buena es adyacente a la persona mala, la persona mala puede simplemente moverse a la derecha y ahora tiene acceso completo a dondequiera que pueda moverse la persona buena. No importa si la persona buena puede llegar, porque la mala también puede. Además, no está permitido reemplazar a una persona buena por una pared, así que no está permitido impedir el movimiento de la persona mala.
Con esta observación, la solución es relativamente simple. Comprobamos esta adyacencia y, si existe, imprimimos “No.” En caso contrario, procedemos rodeando a las personas malas con paredes. Hacemos flood fill (relleno) desde el punto final , y nos aseguramos de que todas las personas buenas hayan sido visitadas. No hace falta comprobar que las personas malas no llegaron, porque rodearlas con paredes es suficiente.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mxN = 55;
char grid[mxN][mxN];
bool visited[mxN][mxN];
int rowMovement[4]{0, 1, 0, -1};
int columnMovement[4]{1, 0, -1, 0};
int N, M;
void floodfill(int r, int c) {
if (r < 0 || r >= N || c < 0 || c >= M) return;
if (grid[r][c] == '#' || visited[r][c]) return;
visited[r][c] = true;
floodfill(r + 1, c);
floodfill(r - 1, c);
floodfill(r, c + 1);
floodfill(r, c - 1);
}
void solve() {
memset(grid, '.', sizeof(grid));
memset(visited, 0, sizeof(visited));
cin >> N >> M;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) { cin >> grid[i][j]; }
}
// rodear a las personas malas
bool ok = true;
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (grid[i][j] == 'B') {
for (int x = 0; x < 4; x++) // recorrer las 4 direcciones
{
int newRow = i + rowMovement[x];
int newColumn = j + columnMovement[x];
// comprobar si está dentro de los límites
if (newRow >= 0 && newRow < N && newColumn >= 0 && newColumn < M) {
if (grid[newRow][newColumn] == 'G') {
cout << "No\n";
return;
}
if (grid[newRow][newColumn] == '.') {
grid[newRow][newColumn] = '#'; // convertirlo en #
}
}
}
}
}
}
floodfill(N - 1, M - 1);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (grid[i][j] == 'G' && !visited[i][j]) {
cout << "No\n";
return;
}
}
}
cout << "Yes\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) { solve(); }
}import java.io.*;
import java.util.*;
public class SolveTheMaze {
static int[] rowMovement = {0, 1, 0, -1}; // derecha, abajo, izquierda, arriba
static int[] columnMovement = {1, 0, -1, 0};
static char[][] grid;
static boolean[][] visited;
static int numRows;
static int numColumns;
static boolean inBoundaries(int newRow, int newColumn) {
if (newRow >= 0 && newRow < numRows) {
if (newColumn >= 0 && newColumn < numColumns) { return true; }
}
return false;
}
static void floodfill(int row, int column) {
visited[row][column] = true;
for (int x = 0; x < 4; x++) { // las 4 direcciones
int newRow = row + rowMovement[x];
int newColumn = column + columnMovement[x];
if (inBoundaries(newRow, newColumn)) { // dentro de los límites
// no visitado, y no #
if (!visited[newRow][newColumn]) {
if (grid[newRow][newColumn] != '#') {
floodfill(newRow, newColumn);
}
}
}
}
}
static String solve() {
// rodear a los malos
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numColumns; j++) {
if (grid[i][j] == 'B') {
for (int x = 0; x < 4; x++) { // las 4 direcciones
int newRow = i + rowMovement[x];
int newColumn = j + columnMovement[x];
// comprobar si está dentro de los límites
if (inBoundaries(newRow, newColumn)) {
if (grid[newRow][newColumn] == 'G') { return "No"; }
if (grid[newRow][newColumn] == '.') {
// convertirlo en #
grid[newRow][newColumn] = '#';
}
}
}
}
}
}
if (grid[numRows - 1][numColumns - 1] != '#') {
// hacer flood fill
floodfill(numRows - 1, numColumns - 1);
}
for (int i = 0; i < numRows; i++) {
for (int j = 0; j < numColumns; j++) {
// devolver falso si encontramos una G no visitada
if (grid[i][j] == 'G' && !visited[i][j]) { return "No"; }
}
}
return "Yes";
}
public static void main(String[] args) {
Kattio io = new Kattio();
int numTestCases = io.nextInt();
for (int x = 0; x < numTestCases; x++) {
numRows = io.nextInt();
numColumns = io.nextInt();
grid = new char[numRows][numColumns];
visited = new boolean[numRows][numColumns];
for (int row = 0; row < numRows; row++) { // leer la grilla
String line = io.next();
for (int column = 0; column < numColumns; column++) {
grid[row][column] = line.charAt(column);
}
}
io.println(solve());
}
io.close();
}
// CodeSnip{Kattio}
}for _ in range(int(input())):
n, m = map(int, input().split())
# Guarda las coordenadas de todas las personas buenas, que iremos quitando a medida que las protegemos.
good_people = set()
grid = []
for r in range(n):
grid.append(list(input().strip()))
for c, char in enumerate(grid[-1]):
if char == "G":
good_people.add((r, c))
visited = [[False] * len(grid[0]) for _ in range(len(grid))]
stack = [(n - 1, m - 1)]
while stack:
i, j = stack.pop()
if visited[i][j]:
continue
visited[i][j] = True
"""
Si una celda adyacente es una persona mala, queremos convertir la celda
actual en una pared. Si una celda adyacente es una persona mala y la celda
actual es una persona buena, no podemos proteger a la persona buena. Solo
agregamos celdas adyacentes a la cola y marcamos a la persona buena como
protegida si descubrimos que no hay personas malas adyacentes.
"""
cells_to_add = []
for new_i, new_j in [(i + 1, j), (i - 1, j), (i, j + 1), (i, j - 1)]:
if not (0 <= new_i < n and 0 <= new_j < m) or visited[new_i][new_j]:
continue
if grid[new_i][new_j] == "." or grid[new_i][new_j] == "G":
cells_to_add.append((new_i, new_j))
elif grid[new_i][new_j] == "B":
break
else:
stack.extend(cells_to_add)
if grid[i][j] == "G":
good_people.discard((i, j))
print("Yes" if not good_people else "No")