이번에 풀어본 문제는
백준 13460번 구슬탈출2 입니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
class Ball
{
int bx,by,rx,ry,cnt;
public Ball(int bx, int by, int rx, int ry, int cnt)
{
this.bx = bx;
this.by = by;
this.rx = rx;
this.ry = ry;
this.cnt = cnt;
}
}
public class Main {
static int n,m;
static char [][] map;
static boolean [][][][] isVis;
static int [] dx = {-1,1,0,0};
static int [] dy = {0,0,-1,1};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
map = new char[n][m];
int bx=0,by=0,rx=0,ry=0;
for(int i = 0; i < n; ++i)
{
String tmp = br.readLine();
for(int j = 0; j < m; ++j)
{
map[i][j] = tmp.charAt(j);
if(map[i][j] == 'B')
{
bx = i;
by= j;
}
else if(map[i][j] == 'R')
{
rx = i;
ry = j;
}
}
}
isVis = new boolean[n][m][n][m];
Queue<Ball> q= new LinkedList<>();
q.add(new Ball(bx,by,rx,ry,1));
boolean exitFlag = false;
loop : while(!q.isEmpty())
{
Ball cur = q.poll();
if(cur.cnt > 10)
{
System.out.print("-1");
return;
}
if(isVis[cur.bx][cur.by][cur.rx][cur.ry]) continue;
for(int i = 0; i < 4; ++i)
{
int b_mx = cur.bx;
int b_my = cur.by;
boolean [] isExit = new boolean[2];
while(true)
{
b_mx += dx[i];
b_my += dy[i];
if(!isValid(b_mx,b_my) || map[b_mx][b_my] == '#')
{
b_mx -= dx[i];
b_my -= dy[i];
break;
}
if(map[b_mx][b_my] == 'O')
{
isExit[0] = true;
break;
}
}
int r_mx = cur.rx;
int r_my = cur.ry;
while(true)
{
r_mx += dx[i];
r_my += dy[i];
if(!isValid(r_mx,r_my) || map[r_mx][r_my] == '#')
{
r_mx -= dx[i];
r_my -= dy[i];
break;
}
if(map[r_mx][r_my] == 'O')
{
isExit[1] = true;
break;
}
}
if(b_mx == cur.bx && b_my == cur.by && r_mx == cur.rx && r_my == cur.ry) continue;
if(isExit[1])
{
if(isExit[0]) continue;
else
{
System.out.print(cur.cnt);
exitFlag = true;
break loop;
}
}
else if(isExit[0]) continue;
if(b_mx == r_mx && b_my == r_my)
{
if(i == 0)
{
if(cur.bx < cur.rx) r_mx += 1;
else b_mx += 1;
}
else if(i == 1)
{
if(cur.bx < cur.rx) b_mx -= 1;
else r_mx -= 1;
}
else if(i == 2)
{
if(cur.by < cur.ry) r_my += 1;
else b_my += 1;
}
else
{
if(cur.by < cur.ry) b_my -= 1;
else r_my -= 1;
}
}
q.add(new Ball(b_mx,b_my,r_mx,r_my,cur.cnt+1));
}
isVis[cur.bx][cur.by][cur.rx][cur.ry] = true;
}
if(!exitFlag) System.out.print("-1");
}
static boolean isValid(int x, int y)
{
return x > 0 && y > 0 && x < n-1 && y < m-1;
}
}
bfs로 풀어보았습니다.
조건이 굉장히 복잡하지만 시키는대로만 하면 어렵지는 않았던 것 같습니다.
우선 두 구슬이 같은선상에 있을 경우가 가장 헷갈렸는데, 일단 굴려놓고 두 구슬이 겹쳐있을 때, 이전 위치를 통해 어떤 구슬을 한칸 뒤로 빼야하는지 결정해줍니다.
두 구슬이 모두 빠지거나 파란 구슬만 빠지는 경우는 제외해주고, 가장 먼저 빨간구슬을 내보내는 경우 결과를 출력하고 종료합니다. 4차원 방문배열을 만들어 각 구슬들의 이동 전 좌표값을 기반으로 방문체크를 해줄 수 있습니다.
정말.. 어이없지만 구멍을 숫자0으로 봐서 잘못된 부분 찾는다고 30분은 버린 것 같습니다 ㅎㅏ ㅎ ㅏ ㅎ ㅎㅎ ㅏㅏ,,,
복잡하지만 구현문제는 머릿속에 뭔가 상황이 그려져서 재밌는 것 같아요! ㅋㅋㅋㅋㅋ
추석이라 할머니댁에 와있지만 시간 짬내서 한문제 풀어보았습니다!
즐추~