메이쁘

(JAVA) 백준 3055번 : 탈출 본문

Algorithm/Baekjoon

(JAVA) 백준 3055번 : 탈출

메이쁘 2020. 4. 21. 02:22

https://www.acmicpc.net/problem/3055

 

3055번: 탈출

문제 사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제일 친한 친구인 비버의 굴로 가능한 빨리 도망가 홍수를 피하려고 한다. 티떱숲의 지도는 R행 C열로 이루어져 있다. 비어있는 곳은 '.'로 표시되어 있고, 물이 차있는 지역은 '*', 돌은 'X'로 표시되어 있다. 비버의 굴은 'D'로, 고슴도치의 위치는 'S'로 나

www.acmicpc.net

 

 

시뮬레이션 문제.

 

 

고슴도치를 이리저리 움직여서 동굴에 들어갈 수 있는 최단 시간을 구하는 문제.

 

 

물, 굴, 돌 이 추가되서 꽤 난이도가 있어보이긴 하지만

 

문제를 유심히 살펴보면

 

전부 고슴도치가 이동할 수 없다는 공통점이 있다.

** 굴은 최종 목적지 이기 때문에 바로 판별할 수 있다.

 

 

또 다른 핵심은

 

여기서 보면

" 물이 찰 예정인 칸으로 이동할 수 없다. " 고 한다.

 

이는 즉 시간이 1초 지났을 때 고슴도치가 이동할 수 없는 곳은

물이 차 있는 곳 + 물의 상하좌우(물이 찰 예정인 칸) 인 곳 + 돌 + 굴 이다.

 

 

마지막으로

시간 초과메모리 초과 오류를 방지하기 위해

 

고슴도치가 지나온 자리는 이동할 수 없다 고 판단하는 것이 좋다. (boolean 변경)

 

 

물론 고슴도치가 이전 자리로 되돌아갈 순 있지만

 

다른 DFS나 BFS에서와 마찬가지로

 

최소 시간을 구할 경우 되돌아간다는 것은 이미 최소가 아니기 때문이다.

 

 

 

매커니즘


 

초기 설정 값

 

-> 좌표를 표현하기 위해 별도의 클래스를 만들어 사용했다.

*** int[2] 변수를 사용해도 무방하다. 가독성을 위해 클래스를 만들었다.

 

-> 입력값을 담는 char[][]

 

-> 이동 가능 여부를 판단하는 boolean[][]

 

-> 상 - 좌 - 하 - 우 순서대로 좌표 값을 바꾸는 moveX int[], moveY int[]

 

-> 고슴도치가 이동해있는 위치 좌표를 담은 Queue<Point>

 

-> 다음 시간에 물이 흐를 것으로 예상되는 위치 좌표를 담은 Queue<Point>

 

 

 

 

 

알고리즘

1) 고슴도치 시작 지점, 도착 지점(동굴) 좌표 얻음.

 

 

2) 초기 물 좌표 Queue 저장

 

 

3) 초기 고슴도치 시작 좌표 Queue 저장

 

 

4) 0초부터 시작. While(True)

 

*** 물 셋팅

4-1) 물 좌표 Queue에서 하나씩 꺼내며 상하좌우로 물 이동 예상 좌표를 파악한 후 boolean[][] 변경.

 

4-2) 예상 좌표를 새로운 물 좌표 Queue에 넣음

 

4-3) 기존 물 좌표 Queue가 빈다면, 새로운 물 좌표 Queue를 기존 물 좌표 Queue로 복사.

 

 

*** 고슴도치 이동

4-4) 고슴도치 위치 Queue에서 하나씩 꺼내며 상하좌우로 고슴도치 이동 가능 여부를 파악

 

4-5) 도착 지점으로 이동 가능한 경우 현재 시간 + 1 리턴.

 

4-6) 이동 가능한 경우 boolean[][] 변경 후 4-2) 와 동일하게 진행

 

4-7) 시간 1초 증가시킨 후 4) 반복

 

 

5) 결과 출력

 

**** 4) While문에서 반드시 고슴도치가 이동할 수 있는 경우가 없을 때를 따져봐야 한다. (고슴도치 Queue Empty)

**** 그래서 없다면 "KAKTUS" 출력.

 

 

 

감사합니다!

 

다들 화이팅하시고

 

좋은 하루 되세요~! ^_^

 

 

소스코드


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
// 탈출 문제
// 시뮬레이션
public class p3055 {
static char[][] map;
static boolean[][] notMoved; // T : 이동 불가능, F : 이동 가능.
static Queue<Point3055> waters;
static int[] moveX = { 0, 1, 0, -1 };
static int[] moveY = { -1, 0, 1, 0 };
static int x, y;
public static void main(String args[]) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
y = Integer.valueOf(st.nextToken());
x = Integer.valueOf(st.nextToken());
map = new char[y][x];
notMoved = new boolean[y][x];
waters = new LinkedList<Point3055>();
// 무조건 D와 S는 하나씩만 주어진다고 했으므로 null로 초기화해도 상관없다.
Point3055 startPoint = null;
Point3055 endPoint = null;
for(int i = 0; i < y; i++) {
st = new StringTokenizer(br.readLine());
String line = st.nextToken();
map[i] = line.toCharArray();
for(int j = 0; j < x; j++) {
switch(map[i][j]) {
case 'D':
endPoint = new Point3055(j, i);
notMoved[i][j] = true;
break;
case 'S':
startPoint = new Point3055(j, i);
break;
case '*':
waters.add(new Point3055(j, i));
notMoved[i][j] = true;
break;
case 'X':
notMoved[i][j] = true;
break;
}
}
}
int result = escape(startPoint, endPoint);
System.out.println(result == -1 ? "KAKTUS" : result);
}
// 고슴도치 탈출 함수
static int escape(Point3055 start, Point3055 end) {
int time = 0;
Queue<Point3055> goSumDoChi = new LinkedList<Point3055>();
goSumDoChi.offer(start);
while(true) {
if(goSumDoChi.isEmpty()) {
return -1;
}
// 물 셋팅
setWaterFlow();
// 고슴도치 이동시키기
Queue<Point3055> nextGoSumDoChi = new LinkedList<Point3055>();
while(!goSumDoChi.isEmpty()) {
Point3055 goSum = goSumDoChi.poll();
for(int i = 0; i < moveX.length; i++) {
int nextX = goSum.x + moveX[i];
int nextY = goSum.y + moveY[i];
// 고슴도치가 이동해서 동굴에 도착할 수 있다면
if(nextX == end.x && nextY == end.y) {
return time + 1;
}
if(validPoint(nextX, nextY)) {
notMoved[nextY][nextX] = true;
nextGoSumDoChi.add(new Point3055(nextX, nextY));
}
}
}
goSumDoChi = nextGoSumDoChi;
time++;
}
}
// 물 상하좌우로 흐르는 것을 notMoved boolean 배열에 나타내는 함수
static void setWaterFlow() {
Queue<Point3055> nextWaters = new LinkedList<Point3055>();
while(!waters.isEmpty()) {
Point3055 water = waters.poll();
for(int i = 0; i < moveX.length; i++) {
int nextX = water.x + moveX[i];
int nextY = water.y + moveY[i];
if(validPoint(nextX, nextY)) {
notMoved[nextY][nextX] = true;
nextWaters.add(new Point3055(nextX, nextY));
}
}
}
waters = nextWaters;
}
// 해당 지점에 이동할 수 있는지(물이든 고슴도치이든) 체크하는 함수
static boolean validPoint(int pointX, int pointY) {
if(pointX < 0 || pointX >= x) {
return false;
}
if(pointY < 0 || pointY >= y) {
return false;
}
if(notMoved[pointY][pointX]) {
return false;
}
return true;
}
}
class Point3055 {
int x;
int y;
Point3055() {}
Point3055(int x, int y) {
this.x = x;
this.y = y;
}
}
view raw p3055.java hosted with ❤ by GitHub

 

 

Comments