Labyrinth
Solución en video
Por David Zhou
Video de YouTube (02I_HdNIfuo)
Código de la solución en video
#include <algorithm>
#include <iostream>
#include <queue>
#include <string>
#include <utility>
#include <vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<string> labyrinth(n);
queue<pair<int, int>> q;
int a_row, a_col, b_row, b_col;
for (int i = 0; i < n; i++) {
cin >> labyrinth[i];
for (int j = 0; j < m; j++) {
if (labyrinth[i][j] == 'A') {
a_row = i;
a_col = j;
q.push({i, j});
} else if (labyrinth[i][j] == 'B') {
b_row = i;
b_col = j;
}
}
}
// Direcciones: Arriba, Derecha, Abajo, Izquierda
vector<int> dirR{-1, 0, 1, 0};
vector<int> dirC{0, 1, 0, -1};
vector<vector<int>> arrive(n, vector<int>(m, -1));
while (!q.empty()) {
int row = q.front().first, col = q.front().second;
q.pop();
for (int i = 0; i < 4; i++) {
int nextR = row + dirR[i], nextC = col + dirC[i];
if (nextR >= 0 && nextR < n && nextC >= 0 && nextC < m &&
labyrinth[nextR][nextC] != '#' && arrive[nextR][nextC] == -1) {
arrive[nextR][nextC] = i;
q.push({nextR, nextC});
}
}
}
if (arrive[b_row][b_col] == -1) {
cout << "NO" << endl;
} else {
string res = "", dir = "URDL";
int row = b_row, col = b_col;
while (row != a_row || col != a_col) {
int ind = arrive[row][col];
res += dir[ind];
row -= dirR[ind];
col -= dirC[ind];
}
reverse(res.begin(), res.end());
cout << "YES\n" << res.length() << "\n" << res << endl;
}
}import java.util.*;
public class Labyrinth {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(), m = sc.nextInt();
sc.nextLine(); // consumir el salto de línea
char[][] labyrinth = new char[n][m];
int[][] arrive = new int[n][m];
for (int[] row : arrive) Arrays.fill(row, -1);
int aRow = -1, aCol = -1, bRow = -1, bCol = -1;
Queue<int[]> q = new LinkedList<>();
for (int i = 0; i < n; i++) {
String line = sc.nextLine();
for (int j = 0; j < m; j++) {
labyrinth[i][j] = line.charAt(j);
if (labyrinth[i][j] == 'A') {
aRow = i;
aCol = j;
q.add(new int[] {i, j});
} else if (labyrinth[i][j] == 'B') {
bRow = i;
bCol = j;
}
}
}
// Direcciones: Arriba, Derecha, Abajo, Izquierda
int[] dirR = {-1, 0, 1, 0};
int[] dirC = {0, 1, 0, -1};
char[] dirChar = {'U', 'R', 'D', 'L'};
while (!q.isEmpty()) {
int[] pos = q.poll();
int row = pos[0], col = pos[1];
for (int i = 0; i < 4; i++) {
int nextR = row + dirR[i], nextC = col + dirC[i];
if (nextR >= 0 && nextR < n && nextC >= 0 && nextC < m &&
labyrinth[nextR][nextC] != '#' && arrive[nextR][nextC] == -1) {
arrive[nextR][nextC] = i;
q.add(new int[] {nextR, nextC});
}
}
}
if (arrive[bRow][bCol] == -1) {
System.out.println("NO");
} else {
StringBuilder res = new StringBuilder();
int row = bRow, col = bCol;
while (row != aRow || col != aCol) {
int move = arrive[row][col];
res.append(dirChar[move]);
row -= dirR[move];
col -= dirC[move];
}
res.reverse();
System.out.println("YES");
System.out.println(res.length());
System.out.println(res.toString());
}
}
}import sys
from collections import deque
input = sys.stdin.readline # entrada más rápida
n, m = map(int, input().split())
labyrinth = []
a_row = a_col = b_row = b_col = -1
for i in range(n):
row = input().strip()
labyrinth.append(row)
for j in range(m):
if row[j] == "A":
a_row, a_col = i, j
elif row[j] == "B":
b_row, b_col = i, j
queue = deque()
queue.append((a_row, a_col))
arrive = [[-1] * m for _ in range(n)]
dir_r = [-1, 0, 1, 0]
dir_c = [0, 1, 0, -1]
dir_char = "URDL"
while queue:
row, col = queue.popleft()
for i in range(4):
next_r = row + dir_r[i]
next_c = col + dir_c[i]
if 0 <= next_r < n and 0 <= next_c < m:
if labyrinth[next_r][next_c] != "#" and arrive[next_r][next_c] == -1:
arrive[next_r][next_c] = i
queue.append((next_r, next_c))
if arrive[b_row][b_col] == -1:
sys.stdout.write("NO\n")
else:
path = []
row, col = b_row, b_col
while (row, col) != (a_row, a_col):
i = arrive[row][col]
path.append(dir_char[i])
row -= dir_r[i]
col -= dir_c[i]
path.reverse()
sys.stdout.write("YES\n")
sys.stdout.write(str(len(path)) + "\n")
sys.stdout.write("".join(path) + "\n")Explicación
Podemos hacer BFS desde el punto de partida de A y comprobar si podemos alcanzar B. Si alcanzamos B, lo habremos hecho por el camino más corto posible.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
#define ii pair<int, int>
#define f first
#define s second
#define mp make_pair
int n, m;
char A[1000][1000];
bool vis[1000][1000];
// previousStep guarda la dirección previa en la que nos movimos para llegar a
// esta celda
int previous_step[1000][1000];
// 0 = arriba, 1 = derecha, 2 = abajo, 3 = izquierda
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
string step_dir = "URDL";
int main() {
cin >> n >> m;
queue<ii> q;
ii begin, end;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> A[i][j];
if (A[i][j] == 'A') {
begin = mp(i, j);
} else if (A[i][j] == 'B') {
end = mp(i, j);
}
}
}
q.push(begin);
vis[begin.f][begin.s] = true;
while (!q.empty()) {
ii u = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
ii v = mp(u.f + dx[i], u.s + dy[i]);
if (v.f < 0 || v.f >= n || v.s < 0 || v.s >= m) continue;
if (A[v.f][v.s] == '#') continue;
if (vis[v.f][v.s]) continue;
vis[v.f][v.s] = true;
previous_step[v.f][v.s] = i;
q.push(v);
}
}
if (vis[end.f][end.s]) {
cout << "YES" << endl;
vector<int> steps;
while (end != begin) {
int p = previous_step[end.f][end.s];
steps.push_back(p);
// deshacer el paso previo para volver a la casilla anterior
// Nótese cómo restamos dx/dy, mientras que antes sumábamos dx/dy
end = mp(end.f - dx[p], end.s - dy[p]);
}
reverse(steps.begin(), steps.end());
cout << steps.size() << endl;
for (char c : steps) { cout << step_dir[c]; }
cout << endl;
} else {
cout << "NO" << endl;
}
}import java.io.*;
import java.util.*;
public class cses1193 {
public static int[] dX = {-1, 0, 0, 1};
public static int[] dY = {0, -1, 1, 0};
public static String dirs = "ULRD";
// Coordenadas de los puntos A y B.
public static point A = new point(-1, -1);
public static point B = new point(-1, -1);
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(System.out);
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
boolean[][] blocked = new boolean[N][M];
boolean[][] visited = new boolean[N][M];
int[][] prevMove = new int[N][M];
// Leer la grilla.
for (int i = 0; i < N; i++) {
char[] S = br.readLine().toCharArray();
for (int j = 0; j < M; j++) {
if (S[j] == '#') {
blocked[i][j] = true;
} else {
blocked[i][j] = false;
if (S[j] == 'A') { A = new point(i, j); }
if (S[j] == 'B') { B = new point(i, j); }
}
}
}
Queue<point> q = new LinkedList<>();
q.add(A);
// BFS empezando desde el punto A.
while (!q.isEmpty()) {
point cur = q.poll();
for (int dir = 0; dir < 4; dir++) {
point next = new point(cur.x + dX[dir], cur.y + dY[dir]);
// Comprobar si el siguiente punto se puede visitar.
if (next.x < 0 || next.y < 0 || next.x >= N || next.y >= M) {
continue;
}
if (blocked[next.x][next.y]) { continue; }
if (visited[next.x][next.y]) { continue; }
visited[next.x][next.y] = true;
prevMove[next.x][next.y] = dir;
q.add(next);
}
}
if (visited[B.x][B.y]) {
pw.println("YES");
ArrayList<Integer> moves = new ArrayList<>();
// Ahora podemos ir hacia atrás desde B para hallar todos los movimientos que hicimos.
while ((A.x != B.x) || (A.y != B.y)) {
int prevDir = prevMove[B.x][B.y];
moves.add(prevDir);
B.x = B.x - dX[prevDir];
B.y = B.y - dY[prevDir];
}
Collections.reverse(moves);
pw.println(moves.size());
for (int i : moves) { pw.print(dirs.charAt(i)); }
} else {
// No podemos alcanzar el punto B.
pw.println("NO");
}
pw.close();
}
public static class point {
public int x, y;
public point(int x, int y) {
this.x = x;
this.y = y;
}
}
}from collections import deque
MAX_N = 1000
STEP_DIR = "URDL"
# 0 = arriba, 1 = derecha, 2 = abajo, 3 = izquierda
DX = [-1, 0, 1, 0]
DY = [0, 1, 0, -1]
vis = [[False for _ in range(MAX_N)] for _ in range(MAX_N)]
# previous_step guarda la dirección previa en la que nos movimos para llegar a esta celda
previous_step = [[-1 for _ in range(MAX_N)] for _ in range(MAX_N)]
n, m = map(int, input().split())
a = []
begin = []
end = []
for i in range(n):
row = list(input())
a.append(row)
for j in range(m):
if a[i][j] == "A":
begin = (i, j)
elif a[i][j] == "B":
end = (i, j)
q = deque()
q.append(begin)
vis[begin[0]][begin[1]] = True
while q:
u = q.popleft()
for i in range(4):
v = (u[0] + DX[i], u[1] + DY[i])
if v[0] < 0 or v[0] >= n or v[1] < 0 or v[1] >= m:
continue
if a[v[0]][v[1]] == "#":
continue
if vis[v[0]][v[1]]:
continue
vis[v[0]][v[1]] = True
previous_step[v[0]][v[1]] = i
q.append(v)
if vis[end[0]][end[1]]:
print("YES")
steps = []
while end != begin:
p = previous_step[end[0]][end[1]]
steps.append(p)
# deshacer el paso previo para volver a la casilla anterior
# nótese cómo restamos DX/DY, mientras que antes sumábamos DX/DY
end = (end[0] - DX[p], end[1] - DY[p])
steps.reverse()
print(len(steps))
print("".join(STEP_DIR[step] for step in steps))
else:
print("NO")