[백준] 3025: 돌 던지기 - JAVA
https://www.acmicpc.net/problem/3025
풀이
주어진 조건에 맞게 위에서부터 돌을 떨어뜨려 최종 상태를 출력하는 문제였다.
단순한 구현으로 하나씩 진행하며 문제를 풀었을 때는 시간초과가 발생했다.
시간초과를 해결하기위해 메모이제이션을 해야했다.
처음 돌을 놓는 열 별로 stack을 만들어 돌이 이동하는 경로를 저장했다.
새로운 돌을 던질 때 stack에 경로가 들어있다면 마지막에서부터 진행하면 된다.
1. 돌의 아랫칸이 벽으로 막혀있거나 가장 아랫줄이라면, 돌은 그 자리에 그대로 멈춰 있는다.
2. 돌의 아랫칸이 비어있다면, 돌은 아랫칸으로 이동한다.
3. 돌의 아랫칸에 돌이 있다면, 돌은 다음과 같이 미끄러진다.
1. 만약 돌의 왼쪽 칸과 왼쪽-아래 칸이 비어있다면, 돌은 왼쪽으로 미끄러진다.
2. 만약 돌이 왼쪽으로 미끄러지지 않았고, 오른쪽 칸과 오른쪽-아래 칸이 비어있다면, 돌은 오른쪽으로 미끄러진다.
3. 위의 두 경우가 아니라면 돌은 그 자리에 멈추고, 다시는 움직이지 않는다.
위의 조건에 따라 drop 메서드를 구현했다.
drop메서드에서 r, c를 Point 클래스로 stack에 넣어가면서 진행했다.
메모리: 85140KB
시간: 808ms
언어: Java 11
코드
import java.io.*;
import java.util.*;
public class Main {
static class Point {
int r;
int c;
public Point(int r, int c) {
this.r = r;
this.c = c;
}
}
static int R, C;
static char[][] board;
static Stack<Point>[] stack;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
R = Integer.parseInt(st.nextToken());
C = Integer.parseInt(st.nextToken());
board = new char[R + 1][C + 1];
for (int i = 1; i <= R; i++) {
String s = br.readLine();
for (int j = 1; j <= C; j++) {
board[i][j] = s.charAt(j - 1);
}
}
stack = new Stack[C + 1];
for (int i = 1; i <= C; i++) {
stack[i] = new Stack<>();
}
int N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; i++) {
int col = Integer.parseInt(br.readLine());
while (!stack[col].isEmpty() &&
board[stack[col].peek().r][stack[col].peek().c] == 'O') {
stack[col].pop();
}
if (stack[col].isEmpty()) {
drop(1, col, col);
} else {
drop(stack[col].peek().r, stack[col].peek().c, col);
}
}
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= R; i++) {
for (int j = 1; j <= C; j++) {
sb.append(board[i][j]);
}
sb.append("\n");
}
System.out.println(sb);
}
private static void drop(int r, int c, int col) {
stack[col].push(new Point(r, c));
// 돌의 아랫칸이 벽으로 막혀있거나 가장 아랫줄이라면, 돌은 그 자리에 그대로 멈춰 있는다.
if (r + 1 <= R && board[r + 1][c] == 'X') {
board[r][c] = 'O';
} else if (r == R) {
board[r][c] = 'O';
}
// 돌의 아랫칸이 비어있다면, 돌은 아랫칸으로 이동한다.
else if (r + 1 <= R && board[r + 1][c] == '.') {
drop(r + 1, c, col);
}
// 돌의 아랫칸에 돌이 있다면,
else if (r + 1 <= R && board[r + 1][c] == 'O') {
// 만약 돌의 왼쪽 칸과 왼쪽-아래 칸이 비어있다면, 돌은 왼쪽으로 미끄러진다.
if (check(r, c - 1) && check(r + 1, c - 1) && board[r][c - 1] == '.' && board[r + 1][c - 1] == '.') {
drop(r + 1, c - 1, col);
}
// 만약 돌이 왼쪽으로 미끄러지지 않았고, 오른쪽 칸과 오른쪽-아래 칸이 비어있다면, 돌은 오른쪽으로 미끄러진다.
else if (check(r, c + 1) && check(r + 1, c + 1) && board[r][c + 1] == '.' && board[r + 1][c + 1] == '.') {
drop(r + 1, c + 1, col);
}
// 위의 두 경우가 아니라면 돌은 그 자리에 멈추고, 다시는 움직이지 않는다.
else {
board[r][c] = 'O';
}
}
}
private static boolean check(int r, int c) {
if (r < 1 || c < 1 || r > R || c > C) {
return false;
}
return true;
}
}