본문 바로가기

Algorithm/Programmers

Level 2: 미로 탈출, 두 개의 BFS 연결

더보기

BFS는 노드와 노드 간 최단 거리를 계산하기 위해서 사용합니다.

문제에서는 시작 노드에서 시작해 레버 노드를 경유하고 최종적으로 도착 노드에 도달해야합니다.

BFS를 연속 실행하고 연속된 BFS 결과를 합산하는 것으로 결과를 도출합니다.

Step 1: 노드를 표현하는 클래스

길 찾기를 위한 경로는 2차원 좌표계-이중 배열로 제공됩니다. 이를 표현하고 저장하기 위한 Node 클래스를 생성합니다.

java
닫기
public class Node { public int x, y; public int cost; public Node(int x, int y, int cost) { ‌‌this.x = x; ‌‌this.y = y; ‌‌this.cost = cost; } }
코드 비고
Line 3 int x, y 2차원 좌표계 위의 x, y 좌표입니다. 각 좌표의 시작 값은 0입니다.
Line 4 int cost BFS 실행 간 이동 거리입니다.

Step 2: BFS 구현

2차원 좌표계에서 시작 지점 bx, by에서 출발해 도착 지점 gx, gy에 도달하는 최단 거리를 계산합니다.

이때 도착 지점에 도달하면 해당 노드까지의 거리(cost)를 리턴하고, 도착하지 못하면 -1을 리턴합니다.

java
닫기
public int bfs(String[] maps, int bx, int by, int gx, int gy) { int[] dx = { 0, 1, 0, -1 }; int[] dy = { -1, 0, 1, 0 }; int h = maps.length; int w = maps[0].length(); int x = bx, y = by; boolean[][] visited = new boolean[h][w]; ‌Queue<Node> q = new LinkedList<>(); ‌q.offer(new Node(x, y, 0)); ‌visited[y][x] = true; while (!q.isEmpty()) { ‌‌Node n = q.poll(); ‌‌if (n.x == gx && n.y == gy) ‌‌‌return n.cost; ‌‌for (int i = 0; i < 4; ++i) ‌‌{ ‌‌‌int nx = n.x + dx[i]; ‌‌‌int ny = n.y + dy[i]; ‌‌‌if (nx < 0 || ny < 0 || nx >= w || ny >= h) ‌‌‌‌continue; ‌‌‌char[] s = maps[ny].toCharArray(); ‌‌‌char c = s[nx]; ‌‌‌if (!visited[ny][nx] && 'X' != c) ‌‌‌{ ‌‌‌‌visited[ny][nx] = true; ‌‌‌‌q.offer(new Node(nx, ny, n.cost + 1)); ‌‌‌} ‌‌} } return -1; }
코드 비고
Line 3:4 int[] dx, dy BFS의 진행 방향을 표현하는 배열입니다.
Line 5:6 int h, w 2차원 좌표계의 높이와 길이입니다.
Line 7 int x = bx, y = by 현재 x, y 좌표입니다. 시작 값은 BFS 실행에서의 출발 좌표입니다.
Line 17:18 if (n.x == gx && n.y == gy) 목표 좌표에 도달하면 이동 거리를 리턴합니다.
Line 27:31 if (!visited[ny][nx] && 'X' != c) 문제의 규칙에 따라서 이동할 수 있는 좌표라면 BFS를 실행합니다.
Line 35 return -1 BFS가 종료되었으나 목표 좌표에 도달하지 못했다면 -1을 리턴합니다.

Step 3: 두 번의 BFS 실행으로 세 개의 노드를 연결

문제에서는 시작 노드에서 시작해 레버 노드를 경유하고 최종적으로 도착 노드에 도달해야합니다.

두 개의 노드를 잇는 경로에서 3자 노드를 반드시 경유하는 길찾기는 다음과 같이 단순화 할 수 있습니다.

더보기

시작 노드에서 3자 노드까지의 최단 거리를 계산합니다.

경유를 위한 3자 노드에서 종료 노드까지의 최단 거리를 계산합니다.

ex, ey
sx, sy
lx, ly
BFS (sx, sy) to (lx, ly) = 10
BFS (lx, ly) to (ex, ey) = 14
BFS = 10+14 = 24

그리고나서 두 개의 최단 거리를 합산합니다.

우선 좌표계로 제공된 이중 배열 maps를 순회하면서 각 노드의 좌표를 구합니다.

그다음 두 번의 BFS를 실행하여 문제의 결과를 도출합니다.

java
닫기
public int solution(String[] maps) { int sx = 0, sy = 0, lx = 0, ly = 0, ex = 0, ey = 0; for (int y = 0; y < maps.length; ++y) { ‌‌char[] s = maps[y].toCharArray(); ‌‌for (int x = 0; x < s.length; ++x) ‌‌{ ‌‌‌char c = s[x]; ‌‌‌switch (c) ‌‌‌{ ‌‌‌‌case 'S' -> { ‌‌‌‌‌sx = x; ‌‌‌‌‌sy = y; ‌‌‌‌} ‌‌‌‌case 'L' -> { ‌‌‌‌‌lx = x; ‌‌‌‌‌ly = y; ‌‌‌‌} ‌‌‌‌case 'E' -> { ‌‌‌‌‌ex = x; ‌‌‌‌‌ey = y; ‌‌‌‌} ‌‌‌} ‌‌} } int toL = bfs(maps, sx, sy, lx, ly); if (toL <= -1) return -1; int toE = bfs(maps, lx, ly, ex, ey); if (toE <= -1) return -1; return toL + toE; }
코드 비고
Line 3:26 int sx, sy, lx, ly, ex, ey 시작 노드(sx, sy)레버 노드(lx, ly) 그리고 도착 노드(ex, ey)를 구합니다.
Line 28:29 toL = bfs() 시작 노드(sx, sy)부터 레버 노드(lx, ly)까지 최단 거리를 BFS로 계산합니다.
만약 경로를 찾지 못하면 -1을 리턴합니다.
Line 30:31 toE = bfs() 레버 노드(lx, ly)부터 도착 노드(ex, ey)까지 최단 거리를 BFS로 계산합니다.
만약 경로를 찾지 못하면 -1을 리턴합니다.
Line 32 return toL + toE 두 번의 BFS 결과를 합산하여 리턴합니다.

Step 4: 전체 코드

각 단계별로 구성된 전체 코드는 다음을 참고합니다.

java
닫기
import java.util.*; public class Solution { public class Node { ‌‌public int x, y; ‌‌public int cost; ‌‌ ‌‌public Node(int x, int y, int cost) ‌‌{ ‌‌‌this.x = x; ‌‌‌this.y = y; ‌‌‌this.cost = cost; ‌‌} } public int solution(String[] maps) { ‌‌int sx = 0, sy = 0, lx = 0, ly = 0, ex = 0, ey = 0; ‌‌for (int y = 0; y < maps.length; ++y) ‌‌{ ‌‌‌char[] s = maps[y].toCharArray(); ‌‌‌for (int x = 0; x < s.length; ++x) ‌‌‌{ ‌‌‌‌char c = s[x]; ‌‌‌‌switch (c) ‌‌‌‌{ ‌‌‌‌‌case 'S' -> { ‌‌‌‌‌‌sx = x; ‌‌‌‌‌‌sy = y; ‌‌‌‌‌} ‌‌‌‌‌case 'L' -> { ‌‌‌‌‌‌lx = x; ‌‌‌‌‌‌ly = y; ‌‌‌‌‌} ‌‌‌‌‌case 'E' -> { ‌‌‌‌‌‌ex = x; ‌‌‌‌‌‌ey = y; ‌‌‌‌‌} ‌‌‌‌} ‌‌‌} ‌‌} ‌‌ ‌‌int toL = bfs(maps, sx, sy, lx, ly); ‌‌if (toL <= -1) return -1; ‌‌int toE = bfs(maps, lx, ly, ex, ey); ‌‌if (toE <= -1) return -1; ‌‌return toL + toE; } public int bfs(String[] maps, int bx, int by, int gx, int gy) { ‌‌int[] dx = { 0, 1, 0, -1 }; ‌‌int[] dy = { -1, 0, 1, 0 }; ‌‌int h = maps.length; ‌‌int w = maps[0].length(); ‌‌int x = bx, y = by; ‌‌boolean[][] visited = new boolean[h][w]; ‌‌ ‌‌Queue<Node> q = new LinkedList<>(); ‌‌q.offer(new Node(x, y, 0)); ‌‌visited[y][x] = true; ‌‌ ‌‌while (!q.isEmpty()) ‌‌{ ‌‌‌Node n = q.poll(); ‌‌‌if (n.x == gx && n.y == gy) ‌‌‌‌return n.cost; ‌‌‌for (int i = 0; i < 4; ++i) ‌‌‌{ ‌‌‌‌int nx = n.x + dx[i]; ‌‌‌‌int ny = n.y + dy[i]; ‌‌‌‌if (nx < 0 || ny < 0 || nx >= w || ny >= h) ‌‌‌‌‌continue; ‌‌‌‌char[] s = maps[ny].toCharArray(); ‌‌‌‌char c = s[nx]; ‌‌‌‌if (!visited[ny][nx] && 'X' != c) ‌‌‌‌{ ‌‌‌‌‌visited[ny][nx] = true; ‌‌‌‌‌q.offer(new Node(nx, ny, n.cost + 1)); ‌‌‌‌} ‌‌‌} ‌‌} ‌‌ ‌‌return -1; } }