[분류]
- 탐색
[문제링크]
[요구사항]
- (1,1), (1,2) 칸을 차지하고 있는 로봇이 (n,n)까지 도착하는데 걸리는 시간을 구해야 합니다.
[풀이]
- 일반적인 bfs문제와 동일하게 접근하면 되지만 조건을 코딩하는 것이 까다롭다.
- 로봇의 두 칸중 하나를 기본 좌표로 잡고 class 정보에 dir를 추가하여 다른 좌표 하나를 유추할 수 있게끔 한다.
- 우선 상하좌우는 보통 문제와 비슷하게 한다.
- 까다로운 것은 회전인데, 로봇의 두 점 중 각 점을 기준으로 잡고 왼쪽으로 회전할 때와 오른쪽으로 회전할 때를 모두 검사하여 queue에 넣는 방식으로 한다.
[코드]
//programmers_60063_블록 이동하기
import java.io.*;
import java.lang.*;
import java.util.*;
public class Main {
final static int dx[] = {0, -1, 0, 1};
final static int dy[] = {1, 0, -1, 0};
final static int drx[] = {1, -1, -1, 1};
final static int dry[] = {1, 1, -1, -1};
static int n;
public static void main(String[] args) throws IOException {
int board[][] = {
{0,0,0,1,1},
{0,0,0,1,0},
{0,1,0,1,1},
{1,1,0,0,1},
{0,0,0,0,0}
};
System.out.println(solution(board));
}
public static int solution(int[][] board) {
n = board.length;
boolean visited[][][] = new boolean[n][n][4];
Queue<Robot> q = new LinkedList<>();
visited[0][0][0] = true;
q.add(new Robot(0, 0, 0, 0));
return bfs(q, visited, board);
}
public static int bfs(Queue<Robot> q, boolean[][][] visited, int[][] board){
int x, y, dir, cnt, ox, oy;
int nx, ny, nox, noy, ndir;
int rx, ry;
while(!q.isEmpty()){
Robot robot = q.poll();
x = robot.x;
y = robot.y;
dir = robot.dir;
cnt = robot.cnt;
ox = robot.x + dx[dir];
oy = robot.y + dy[dir];
if(isFinish(x,y) || isFinish(ox, oy)) return cnt;
for(int i=0;i<4;i++){//상하좌우 이동
nx = x + dx[i];
ny = y + dy[i];
nox = ox + dx[i];
noy = oy + dy[i];
if(!inBound(nx, ny) || !inBound(nox, noy)) continue;
if(board[nx][ny]==1 || board[nox][noy]==1) continue;
if(visited[nx][ny][dir]) continue;
visited[nx][ny][dir]=true;
q.add(new Robot(nx, ny, dir, cnt+1));
}
for(int i=1;i<4;i+=2){//90도 회전 x,y기준
ndir = (dir + i)%4;
nox = x+dx[ndir];
noy = y+dy[ndir];
int tempDir = (i==1) ? ndir:dir;
rx = x + drx[tempDir];
ry = y + dry[tempDir];
if(!inBound(nox, noy) || !inBound(rx, ry)) continue;
if(board[nox][noy] == 1 || board[rx][ry]==1) continue;
if(visited[x][y][ndir]) continue;
visited[x][y][ndir] = true;
q.add(new Robot(x, y, ndir, cnt+1));
}
dir = (dir+2)%4;
for(int i=1;i<4;i+=2){//90도 회전 , ox, oy기준
ndir = (dir + i)%4;
nx = ox+dx[ndir];
ny = oy+dy[ndir];
int tempDir = (i==1) ? ndir:dir;
rx = ox + drx[tempDir];
ry = oy + dry[tempDir];
ndir = (ndir + 2) % 4;
if(!inBound(nx, ny) || !inBound(rx, ry)) continue;
if(board[nx][ny] == 1 || board[rx][ry]==1) continue;
if(visited[nx][ny][ndir]) continue;//nx,ny쓰는 이유는 그 점을 기준점으로 생각해야해서
visited[nx][ny][ndir] = true;
q.add(new Robot(nx, ny, ndir, cnt+1));
}
}
return -1;
}
public static boolean inBound(int x, int y){
return x>=0 && y>=0 && x<n && y<n;
}
public static boolean isFinish(int x, int y){
return x==n-1 && y==n-1;
}
public static class Robot{
int x;
int y;
int dir;
int cnt;
public Robot(int x, int y, int dir, int cnt){
this.x = x;
this.y = y;
this.dir = dir;
this.cnt = cnt;
}
}
}
[통과여부]
[느낀점]
사실 bfs와 관련된 문제는 거의 비슷해서 괜찮다고 생각했는지 난이도가 조금 높아지니 코드로 구현하는 것이 어렵게 느껴졌다..