전체 방문자
오늘
어제
모달조아
Better than yesterday
모달조아
  • 분류 전체보기 (147)
    • PS (86)
      • BOJ (79)
      • 프로그래머스 (6)
    • 이론 (41)
      • 자료구조 (2)
      • 알고리즘 (8)
      • 데이터베이스 (1)
      • 운영체제 (1)
      • 네트워크 (3)
      • 디자인패턴 (7)
      • Java (13)
      • Spring (4)
      • JPA (1)
      • Git (1)
    • 개발 (18)
    • 프로젝트 (1)
    • 기록 (0)
      • 후기 (0)
    • etc (1)

최근 글

티스토리

hELLO · Designed By 정상우.
모달조아

Better than yesterday

PS/BOJ

BOJ 11559 Puyo Puyo [Java]

2022. 2. 9. 19:39

BOJ 11559 Puyo Puyo

1. 문제 링크

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

2. 문제 해설

문제에서 요구하는 구현해야할 기능을 크게 3가지로 나누어보겠다.

1. 터트릴 뿌요를 파악하기 - bfs 메서드
: 같은 색 뿌요가 4개 이상 연속되는 경우를 찾아야한다. bfs, dfs를 이용하면 되겠다는 생각이 들었는데 dfs를 이용하면 ㅗ, ㅜ 같은 모양으로 연속되있는 경우를 처리하기가 까다롭기에 bfs를 이용하기로 결정하였다. 같은 색 뿌요가 연속되는 경우 list에 담아 list의 크기가 4 이상이면 터트릴 수 있고 아닌 경우는 터트릴 수 없는 방식으로 처리하고자 하였다.

2. 뿌요를 터트리기 - explode 메서드
: list에 담겨 있는 뿌요를 빈 칸으로 만들어주면 된다. 간단하다.

3. 뿌요를 터트린 후, 뿌요들을 내려주기 - goDown 메서드
: 첫번째 열, 맨 밑 행의 칸부터 탐색한다. 기준이 되는 칸이 빈 칸이 아니면 내려줄 필요가 없다. 빈 칸이라면 위의 뿌요들을 내려줘야하므로 그 위의 행들을 탐색한다. 그 위의 칸이 빈 칸이면 내려줄 뿌요가 없는 것이므로 넘어간다. 빈 칸이 아니면 기준이 되는 칸에 뿌요 값을 입력해주고, 뿌요가 있던 칸을 빈 칸으로 만들어준다.

위 기능들을 이용하여 어떻게 처리할지 전체적인 흐름을 살펴보자. 밑의 코드의 45~70줄에 관련된 내용이다.
필드의 모든 칸을 돌면서 뿌요가 있는 칸에서 bfs를 해준다. 같은 색의 연속된 뿌요가 4개 이상이면 폭발시켜준다. 필드 전체를 다 돌아보고 폭발한 적이 있으면 연쇄 횟수를 추가해주고 뿌요들을 내려준다. 폭발한 적이 없다면 더 이상 폭발할 것이 없는 것이므로 연쇄를 중단한다.
이 과정에서 주의해야할 것이 2가지 있다. 첫번째는 bfs에 사용하는 vis배열을 매 연쇄마다 초기화해줘야한다. 연쇄마다 필드와 뿌요 상태가 달라지므로 당연히 매번 초기화해줘야한다. 두번째는 bfs를 한번 마무리할 때마다 list를 비워줘야하는 것이다. 이 부분을 놓쳐서 조금 고생하였다. bfs가 끝났을 때 list를 비워주지 않으면 list에 뿌요가 계속 쌓여서 폭발이 일어나지 않아야할 상황에서도 폭발이 일어나게 된다.

3. 코드 보기

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
    static class Point {
        int r, c;

        public Point(int r, int c) {
            this.r = r;
            this.c = c;
        }
    }

    static char[][] field;
    static boolean[][] vis;
    static int[] dr = {0, 1, 0, -1};
    static int[] dc = {1, 0, -1, 0};
    static ArrayList<Point> list;
    static int ans = 0;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        field = new char[12][6];
        list = new ArrayList<>();

        for (int i = 0; i < 12; i++) {
            char[] tmp = br.readLine().toCharArray();

            for (int j = 0; j < 6; j++) {
                field[i][j] = tmp[j];
            }
        }

        solve();

        bw.write(Integer.toString(ans));
        br.close();
        bw.close();
    }

    static void solve() {
        while (true) { // 연쇄를 계속 반복
            vis = new boolean[12][6]; // 새로운 연쇄마다 vis 배열을 초기화해야한다
            boolean explosion = false; // 폭발했는지 여부를 표시

            for (int i = 0; i < 12; i++) { // field 를 돌면서 같은 색의 뿌요가 4개 이상 붙어있는지 탐색
                for (int j = 0; j < 6; j++) {
                    if (field[i][j] != '.') {
                        if (bfs(i, j)) { // 같은 색의 뿌요가 4개 이상이면
                            explode(); // 폭발시킨다
                            explosion = true;
                        }

                        list.clear(); // 뿌요를 폭발시켰다면 리스트를 초기화한다
                    }
                }
            }

            if (explosion) { // 폭발을 했다면
                goDown(); // 뿌요들을 떨어트린다
                ans++;
            } else { // 더 이상 폭발할 뿌요가 없으면 탈출
                break;
            }
        }
    }

    static boolean bfs(int r, int c) { // (r,c)에서 시작하여 탐색하면서 같은 색의 연속된 뿌요를 list 에 넣어준다
        Queue<Point> q = new LinkedList<>();
        q.add(new Point(r, c));
        vis[r][c] = true;
        list.add(new Point(r, c));

        while (!q.isEmpty()) {
            Point cur = q.poll();
            char curColor = field[cur.r][cur.c];

            for (int i = 0; i < 4; i++) {
                int nr = cur.r + dr[i];
                int nc = cur.c + dc[i];

                if (nr < 0 || nc < 0 || nr >= 12 || nc >= 6 || curColor != field[nr][nc] || vis[nr][nc]) { // 범위를 벗어나거나, 연속된 색이 아니거나, 이미 방문한 곳이면 넘어감
                    continue;
                }

                q.add(new Point(nr, nc));
                vis[nr][nc] = true;
                list.add(new Point(nr, nc));
            }
        }

        if (list.size() >= 4) { // 같은 색의 연속된 뿌요가 4개 이상이면 참, 아니면 거짓
            return true;
        } else {
            return false;
        }
    }

    static void explode() {
        for (Point cur : list) {
            field[cur.r][cur.c] = '.';
        }
    }

    static void goDown() {
        for (int i = 0; i < 6; i++) { // 열
            for (int j = 11; j > 0; j--) { // 끝 행에서부터 위로 올라가며 탐색
                if (field[j][i] != '.') { // 밑 부분에 빈 칸이 있고 그 위에 뿌요가 있을 경우 내려줘야하므로, 빈 칸이 아닌 경우는 넘어감
                    continue;
                }

                for (int k = j - 1; k >= 0; k--) { // 기준이 되는 칸부터 위로 올라가며 탐색
                    if (field[k][i] == '.') { // 내릴 칸은 빈 칸이면 안된다
                        continue;
                    }

                    field[j][i] = field[k][i];
                    field[k][i] = '.';
                    break;
                }
            }
        }
    }
}
저작자표시 (새창열림)

'PS > BOJ' 카테고리의 다른 글

BOJ 2457 공주님의 정원 [Java]  (0) 2022.03.03
BOJ 9663 N-Queen [Java]  (0) 2022.02.13
BOJ 15686 치킨 배달 [Java]  (0) 2022.02.01
BOJ 1260 DFS와 BFS [Java]  (0) 2022.01.31
BOJ 2004 조합 0의 개수 [Java]  (0) 2022.01.26
    'PS/BOJ' 카테고리의 다른 글
    • BOJ 2457 공주님의 정원 [Java]
    • BOJ 9663 N-Queen [Java]
    • BOJ 15686 치킨 배달 [Java]
    • BOJ 1260 DFS와 BFS [Java]
    모달조아
    모달조아

    티스토리툴바