[Gold I] 구슬 탈출 2 - 13460
성능 요약
메모리: 17976 KB, 시간: 152 ms
분류
너비 우선 탐색, 그래프 이론, 그래프 탐색, 구현, 시뮬레이션
제출 일자
2023년 11월 15일 15:07:16
문제 설명
스타트링크에서 판매하는 어린이용 장난감 중에서 가장 인기가 많은 제품은 구슬 탈출이다. 구슬 탈출은 직사각형 보드에 빨간 구슬과 파란 구슬을 하나씩 넣은 다음, 빨간 구슬을 구멍을 통해 빼내는 게임이다.
보드의 세로 크기는 N, 가로 크기는 M이고, 편의상 1×1크기의 칸으로 나누어져 있다. 가장 바깥 행과 열은 모두 막혀져 있고, 보드에는 구멍이 하나 있다. 빨간 구슬과 파란 구슬의 크기는 보드에서 1×1크기의 칸을 가득 채우는 사이즈이고, 각각 하나씩 들어가 있다. 게임의 목표는 빨간 구슬을 구멍을 통해서 빼내는 것이다. 이때, 파란 구슬이 구멍에 들어가면 안 된다.
이때, 구슬을 손으로 건드릴 수는 없고, 중력을 이용해서 이리 저리 굴려야 한다. 왼쪽으로 기울이기, 오른쪽으로 기울이기, 위쪽으로 기울이기, 아래쪽으로 기울이기와 같은 네 가지 동작이 가능하다.
각각의 동작에서 공은 동시에 움직인다. 빨간 구슬이 구멍에 빠지면 성공이지만, 파란 구슬이 구멍에 빠지면 실패이다. 빨간 구슬과 파란 구슬이 동시에 구멍에 빠져도 실패이다. 빨간 구슬과 파란 구슬은 동시에 같은 칸에 있을 수 없다. 또, 빨간 구슬과 파란 구슬의 크기는 한 칸을 모두 차지한다. 기울이는 동작을 그만하는 것은 더 이상 구슬이 움직이지 않을 때 까지이다.
보드의 상태가 주어졌을 때, 최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 구하는 프로그램을 작성하시오.
입력
첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.
', '#
', 'O
', 'R
', 'B
' 로 이루어져 있다. '.
'은 빈 칸을 의미하고, '#
'은 공이 이동할 수 없는 장애물 또는 벽을 의미하며, 'O
'는 구멍의 위치를 의미한다. 'R
'은 빨간 구슬의 위치, 'B
'는 파란 구슬의 위치이다.
입력되는 모든 보드의 가장자리에는 모두 '#
'이 있다. 구멍의 개수는 한 개 이며, 빨간 구슬과 파란 구슬은 항상 1개가 주어진다.
출력
최소 몇 번 만에 빨간 구슬을 구멍을 통해 빼낼 수 있는지 출력한다. 만약, 10번 이하로 움직여서 빨간 구슬을 구멍을 통해 빼낼 수 없으면 -1을 출력한다.
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class Main{
// 공의 위치를 저장하는 클래스
static class Point{
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y= y;
}
}
// 게임의 상황을 저장하는 Game 클래스
static class Game{
Point red;
Point blue;
int count;
public Game(Point red, Point blue, int count) {
this.red = red;
this.blue = blue;
this.count = count;
}
}
static int n,m;
static char[][] map;
static int result;
// 방향 벡터
static int[] dirX = {-1,1,0,0};
static int[] dirY = {0,0,-1,1};
public static void main(String[] args) throws IOException{
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
map = new char[n][m];
// 최소값을 찾기 위해서 값은 MAX_VALUE로 넣어준다.
result = Integer.MAX_VALUE;
Point blue = null;
Point red = null;
for(int i = 0; i < n; i++){
String line = sc.next();
for(int j = 0; j < m; j++){
map[i][j] = line.charAt(j);
// 공들의 위치를 저장한 후 map에는 공이 없도록 초기화해줌
if(map[i][j] == 'B'){
map[i][j] = '.';
blue = new Point(i, j);
}else if(map[i][j] == 'R'){
map[i][j] = '.';
red = new Point(i, j);
}
}
}
bfs(new Game(red, blue, 0));
System.out.println(result == Integer.MAX_VALUE ? -1 : result);
}
private static void bfs(Game game) {
// 상황을 저장하기 위한 Queue를 생성
Queue<Game> queue = new LinkedList<>();
queue.offer(game);
// queue가 빌 때 까지 돌려준다.
while(!queue.isEmpty()){
Game curGame = queue.poll();
Point curRed = curGame.red;
Point curBlue = curGame.blue;
// count가 9이상이라면 10번이상 한 것이므로 의미가 없다. 종료해주기
if(curGame.count > 9){
continue;
}
// 방향별로 한번씩 기울여줌
for(int i = 0; i < 4; i++){
// 게임 시작 할 때 위치를 설정해줌
map[curRed.x][curRed.y] = 'R';
map[curBlue.x][curBlue.y] = 'B';
// 옮길 위치를 만들어준다.
int nRX = curRed.x;
int nRY = curRed.y;
int nBX = curBlue.x;
int nBY = curBlue.y;
// 공이 들어갔는지 안들어갔는지를 확인해줌
boolean blueGoal = false;
boolean redGoal = false;
while(true){
// 움직였는지 확인하는 상태 움직이지 않는다면 종료시켜줌
boolean change = false;
// 빨간 공이 들어가있다면 더 이상 움직일 로직이 필요 x
if(!redGoal){
char nextRed = map[nRX + dirX[i]][nRY+dirY[i]];
if(nextRed == '.'){
// 빈 공간이면 이동 시켜준다.
change = true;
map[nRX+dirX[i]][nRY+dirY[i]] = 'R';
map[nRX][nRY] = '.';
nRX += dirX[i];
nRY += dirY[i];
} else if(nextRed == 'O'){
// 구멍이라면 넣어주고 위치에 공을 치워준다.
map[nRX][nRY] = '.';
redGoal = true;
change = true;
}
}
if(!blueGoal){
char nextBlue = map[nBX + dirX[i]][nBY+dirY[i]];
if(nextBlue == '.'){
// 빈 공간이면 이동 시켜준다.
change = true;
map[nBX+dirX[i]][nBY+dirY[i]] = 'B';
map[nBX][nBY] = '.';
nBX += dirX[i];
nBY += dirY[i];
} else if(nextBlue == 'O'){
// 파란 공이 들어갔다면 더이상 while문이 의미가 없으므로 break
map[nBX][nBY] = '.';
blueGoal = true;
break;
}
}
// 변화가 없다면 반복문은 종료 시켜준다.
if(!change) break;
}
// 공이 놓여진 위치에서 공을 없애준다.
map[nRX][nRY] = '.';
map[nBX][nBY] = '.';
// 파랑공이 들어갔다면 의미가 없으므로 continue;
if(blueGoal){
continue;
}
// 빨간공이 들어간 경우의 수가 더 빨리 들어간 경우가 있을 수 있으므로
// Min처리하고 return은 하지않는다.
if(redGoal){
result = Math.min(result,curGame.count+1);
}
// 기존 위치와 아예 똑같다면 공을 넣어주지 않음
if(nRX == curRed.x && nRY == curRed.y && nBX == curBlue.x && nBY == curBlue.y){
continue;
}
// 옮겨진 좌표를 게임에 저장해준다.
queue.offer(new Game(new Point(nRX, nRY), new Point(nBX, nBY), curGame.count+1));
}
}
}
}
'알고리즘 - Baekjoon > Gold' 카테고리의 다른 글
[백준] 16928번 : 뱀과 사다리 게임 Gold5(골드 5) - JAVA[자바] (0) | 2023.11.17 |
---|---|
[백준] 12865번 : 평범한 배낭 Gold V(골드5) - JAVA[자바] (1) | 2023.11.16 |
[백준] 1941번 : 소문난 칠공주 Gold3(골드3) - JAVA[자바] (0) | 2023.11.09 |
[백준] 11401번 : 이항 계수 3 Gold1(골드1) - JAVA[자바] (0) | 2023.11.08 |
[백준] 2294번 : 동전2 Gold5(골드5) - JAVA[자바] (1) | 2023.11.01 |