문제 링크 : https://www.acmicpc.net/problem/13459
13459번: 구슬 탈출
첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'
www.acmicpc.net
문제
스타트링크에서 판매하는 어린이용 장난감 중에서 가장 인기가 많은 제품은 구슬 탈출이다. 구슬 탈출은 직사각형 보드에 빨간 구슬과 파란 구슬을 하나씩 넣은 다음, 빨간 구슬을 구멍을 통해 빼내는 게임이다.
보드의 세로 크기는 N, 가로 크기는 M이고, 편의상 1×1크기의 칸으로 나누어져 있다. 가장 바깥 행과 열은 모두 막혀져 있고, 보드에는 구멍이 하나 있다. 빨간 구슬과 파란 구슬의 크기는 보드에서 1×1크기의 칸을 가득 채우는 사이즈이고, 각각 하나씩 들어가 있다. 게임의 목표는 빨간 구슬을 구멍을 통해서 빼내는 것이다. 이때, 파란 구슬이 구멍에 들어가면 안 된다.
이때, 구슬을 손으로 건드릴 수는 없고, 중력을 이용해서 이리 저리 굴려야 한다. 왼쪽으로 기울이기, 오른쪽으로 기울이기, 위쪽으로 기울이기, 아래쪽으로 기울이기와 같은 네 가지 동작이 가능하다.
각각의 동작에서 공은 동시에 움직인다. 빨간 구슬이 구멍에 빠지면 성공이지만, 파란 구슬이 구멍에 빠지면 실패이다. 빨간 구슬과 파란 구슬이 동시에 구멍에 빠져도 실패이다. 빨간 구슬과 파란 구슬은 동시에 같은 칸에 있을 수 없다. 또, 빨간 구슬과 파란 구슬의 크기는 한 칸을 모두 차지한다. 기울이는 동작을 그만하는 것은 더 이상 구슬이 움직이지 않을 때 까지이다.
보드의 상태가 주어졌을 때, 10번 이하로 빨간 구슬을 구멍을 통해 빼낼 수 있는지 구하는 프로그램을 작성하시오.
입력
스타트링크에서 판매하는 어린이용 장난감 중에서 가장 인기가 많은 제품은 구슬 탈출이다. 구슬 탈출은 직사각형 보드에 빨간 구슬과 파란 구슬을 하나씩 넣은 다음, 빨간 구슬을 구멍을 통해 빼내는 게임이다.
보드의 세로 크기는 N, 가로 크기는 M이고, 편의상 1×1크기의 칸으로 나누어져 있다. 가장 바깥 행과 열은 모두 막혀져 있고, 보드에는 구멍이 하나 있다. 빨간 구슬과 파란 구슬의 크기는 보드에서 1×1크기의 칸을 가득 채우는 사이즈이고, 각각 하나씩 들어가 있다. 게임의 목표는 빨간 구슬을 구멍을 통해서 빼내는 것이다. 이때, 파란 구슬이 구멍에 들어가면 안 된다.
이때, 구슬을 손으로 건드릴 수는 없고, 중력을 이용해서 이리 저리 굴려야 한다. 왼쪽으로 기울이기, 오른쪽으로 기울이기, 위쪽으로 기울이기, 아래쪽으로 기울이기와 같은 네 가지 동작이 가능하다.
각각의 동작에서 공은 동시에 움직인다. 빨간 구슬이 구멍에 빠지면 성공이지만, 파란 구슬이 구멍에 빠지면 실패이다. 빨간 구슬과 파란 구슬이 동시에 구멍에 빠져도 실패이다. 빨간 구슬과 파란 구슬은 동시에 같은 칸에 있을 수 없다. 또, 빨간 구슬과 파란 구슬의 크기는 한 칸을 모두 차지한다. 기울이는 동작을 그만하는 것은 더 이상 구슬이 움직이지 않을 때 까지이다.
보드의 상태가 주어졌을 때, 10번 이하로 빨간 구슬을 구멍을 통해 빼낼 수 있는지 구하는 프로그램을 작성하시오.
출력
파란 구슬을 구멍에 넣지 않으면서 빨간 구슬을 10번 이하로 움직여서 빼낼 수 있으면 1을 없으면 0을 출력한다.
예제 입력 1
5 5
#####
#..B#
#.#.#
#RO.#
#####
예제 출력 1
1
예제 입력 2
7 7
#######
#...RB#
#.#####
#.....#
#####.#
#O....#
#######
예제 출력 2
1
문제 풀이
bfs를 이용한 시뮬레이션 문제였다.
map 정보를 입력받고, 기울인 방향에 대해서 bfs를 돌려가면서 조건에 맞는 결과를 만들어내었다.
기울인 방향에 따라서 빨간 구슬과 파란 구슬 중 먼저 움직이는 구슬을 찾고 그 구슬이 더이상 움직이지 않을 때까지 움직인다.
구슬이 끝까지 움직이게 되면 두 구슬이 같은 위치에 있을 수 있기 때문에 나중에 움직인 구슬을 한 칸 옆으로 이동시켜 주었다.
모든 경우를 해당 방법으로 움직여준 후 빨간 구슬만 구멍으로 들어가는 경우가 존재하는지 확인해 주었다.
코드
import java.io.*;
import java.util.*;
public class Main_BJ_13459_구슬탈출 {
static int N, M;
static char[][] map;
static int[] r, b;
static boolean[][][][] visited;
static int[][] D = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 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];
visited = new boolean[N][M][N][M];
r = new int[2];
b = new int[2];
for (int i = 0; i < N; i++) {
String str = br.readLine();
for (int j = 0; j < M; j++) {
char c = str.charAt(j);
if (c == 'R') {
r[0] = i;
r[1] = j;
} else if (c == 'B') {
b[0] = i;
b[1] = j;
}
map[i][j] = c;
}
}
System.out.println(bfs());
}
static int bfs() {
Queue<int[]> queue = new LinkedList<int[]>();
queue.offer(new int[] { r[0], r[1], b[0], b[1] });
int cnt = 0;
while (!queue.isEmpty() && cnt < 10) {
int len = queue.size();
for (int i = 0; i < len; i++) {
int[] now = queue.poll();
for (int d = 0; d < 4; d++) {
int[] cur = now.clone();
if(move(cur, d)) {
if (map[cur[0]][cur[1]] == 'O') return 1;
if(visited[cur[0]][cur[1]][cur[2]][cur[3]]) continue;
visited[cur[0]][cur[1]][cur[2]][cur[3]] = true;
queue.add(new int [] {cur[0], cur[1], cur[2], cur[3]});
}
}
}
cnt++;
}
return 0;
}
static boolean move(int [] cur, int d) {
boolean redFirst = false;
if (d == 0 && cur[0] < cur[2]) redFirst = true;
if (d == 1 && cur[0] > cur[2]) redFirst = true;
if (d == 2 && cur[1] < cur[3]) redFirst = true;
if (d == 3 && cur[1] > cur[3]) redFirst = true;
int nx = cur[0];
int ny = cur[1];
while (true) {
nx += D[d][0];
ny += D[d][1];
if (map[nx][ny] == '#') break;
cur[0] = nx;
cur[1] = ny;
if (map[nx][ny] == 'O') break;
}
nx = cur[2];
ny = cur[3];
while(true) {
nx += D[d][0];
ny += D[d][1];
if (map[nx][ny] == '#') break;
cur[2] = nx;
cur[3] = ny;
if (map[nx][ny] == 'O') break;
}
if (map[cur[2]][cur[3]] == 'O') return false;
if (cur[0] == cur[2] && cur[1] == cur[3]) {
switch(d) {
case 0:
if (redFirst) cur[2]++;
else cur[0]++;
break;
case 1:
if (redFirst) cur[2]--;
else cur[0]--;
break;
case 2:
if (redFirst) cur[3]++;
else cur[1]++;
break;
case 3:
if (redFirst) cur[3]--;
else cur[1]--;
break;
}
}
return true;
}
}
'JAVA > 알고리즘 문제풀이' 카테고리의 다른 글
[JAVA] boj 1302 베스트셀러 (0) | 2021.12.26 |
---|---|
[JAVA] boj 1339 단어수학 (0) | 2021.12.26 |
[JAVA] boj 2146 다리 만들기 (0) | 2021.12.17 |
[JAVA] boj 1726 로봇 (0) | 2021.12.15 |
[JAVA] boj 10819 차이를 최대로 (0) | 2021.12.15 |