[BaekJoon] 20061 모노미노도미노2 (Java)

오태호·2023년 4월 8일
0

백준 알고리즘

목록 보기
194/395
post-thumbnail

1.  문제 링크

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

2.  문제













3.  소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {
    static int N, point;
    static Block[] blocks;
    static boolean[][] blue, green;

    static void input() {
        Reader scanner = new Reader();

        N = scanner.nextInt();
        blocks = new Block[N];
        blue = new boolean[4][6];
        green = new boolean[6][4];

        for(int block = 0; block < N; block++) {
            int blockType = scanner.nextInt(), x = scanner.nextInt(), y = scanner.nextInt();
            blocks[block] = new Block(x, y, blockType);
        }
    }

    static void solution() {
        for(Block block : blocks) oneTurn(block);

        StringBuilder sb = new StringBuilder();
        sb.append(point).append('\n').append(countBlockNum());
        System.out.println(sb);
    }

    static int countBlockNum() {
        int count = 0;
        for(int row = 0; row < green.length; row++) {
            for(int col = 0; col < green[row].length; col++) {
                if(green[row][col]) count++;
                if(blue[col][row]) count++;
            }
        }

        return count;
    }

    static void oneTurn(Block block) {
        moveInGreen(block);
        moveInBlue(block);
    }

    static void moveInGreen(Block block) {
        // 블럭 타입이 1 또는 3이라면 해당 열만 확인
        // 0부터 시작해서 블럭이 있는 곳을 찾음
        // 해당 위치 직전에 블럭을 놓고 만약 블럭 타입이 3이라면 그 전 위치에도 블럭을 놓는다
        if(block.blockType == 1 || block.blockType == 3) {
            int row, col = block.y;
            for(row = 0; row < green.length; row++)
                if(green[row][col]) break;
            row--;

            green[row][col] = true;
            if(block.blockType == 3) green[row - 1][col] = true;
        } else { // 블럭 타입이 2라면
            // 0부터 시작해서 블럭이 있는 곳을 찾는데,
            // 해당 열과 다음 열까지 확인하여 해당 위치 직전에 해당 열 및 다음 열에 블럭을 놓는다
            int row, col = block.y;
            for(row = 0; row < green.length; row++)
                if(green[row][col] || green[row][col + 1]) break;
            row--;

            green[row][col] = green[row][col + 1] = true;
        }

        // 하나의 행이 모두 블럭으로 되어있는 곳을 찾는다
        for(int row = 0; row < green.length; row++) {
            boolean flag = true;
            for(int col = 0; col < green[row].length; col++) {
                if(!green[row][col]) {
                    flag = false;
                    break;
                }
            }

            // 만약 해당 행이 모두 블럭으로 되어 있다면
            // 모든 블럭을 한 줄씩 내리고 point를 1 증가시킨다
            if(flag) {
                Arrays.fill(green[row], false);
                if(row != 0) {
                    for(int prevRow = row - 1; prevRow >= 0; prevRow--)
                        green[prevRow + 1] = green[prevRow].clone();
                    Arrays.fill(green[0], false);
                }
                point++;
            }
        }

        // 흐린 영역에 블럭이 위치하는지 찾아본다
        for(int row = 0; row <= 1; row++) {
            boolean flag = false;
            for(int col = 0; col < green[row].length; col++) {
                if(green[row][col]) {
                    flag = true;
                    break;
                }
            }

            // 해당 행에 블럭이 존재한다면
            // 마지막 줄을 제거하고 모든 블럭을 아래로 한 줄씩 내린다
            if(flag) {
                for(int prevRow = green.length - 1; prevRow > 0; prevRow--)
                    green[prevRow] = green[prevRow - 1].clone();
                Arrays.fill(green[row], false);
            }
        }
    }

    static void moveInBlue(Block block) {
        // 블럭 타입이 1 또는 2이라면 해당 행만 확인
        // 0부터 시작해서 블럭이 있는 곳을 찾음
        // 해당 위치 직전에 블럭을 놓고 만약 블럭 타입이 2이라면 그 전 위치에도 블럭을 놓는다
        if(block.blockType == 1 || block.blockType == 2) {
            int row = block.x, col;
            for(col = 0; col < blue[0].length; col++)
                if(blue[row][col]) break;
            col--;

            blue[row][col] = true;
            if(block.blockType == 2) blue[row][col - 1] = true;
        } else { // 블럭 타입이 3이라면
            // 0부터 시작해서 블럭이 있는 곳을 찾는데,
            // 해당 행과 다음 행까지 확인하여 해당 위치 직전에 해당 행 및 다음 행에 블럭을 놓는다
            int row = block.x, col;
            for(col = 0; col < blue[0].length; col++)
                if(blue[row][col] || blue[row + 1][col]) break;
            col--;

            blue[row][col] = blue[row + 1][col] = true;
        }

        // 하나의 열이 모두 블럭으로 되어있는 곳을 찾는다
        for(int col = 0; col < blue[0].length; col++) {
            boolean flag = true;
            for(int row = 0; row < blue.length; row++) {
                if(!blue[row][col]) {
                    flag = false;
                    break;
                }
            }

            // 만약 해당 열이 모두 블럭으로 되어 있다면
            // 모든 블럭을 한 줄씩 오른쪽으로 밀고 point를 1 증가시킨다
            if(flag) {
                for(int row = 0; row < blue.length; row++) blue[row][col] = false;
                if(col != 0) {
                    for(int prevCol = col - 1; prevCol >= 0; prevCol--) {
                        for(int row = 0; row < blue.length; row++)
                            blue[row][prevCol + 1] = blue[row][prevCol];
                    }
                    for(int row = 0; row < blue.length; row++)
                        blue[row][0] = false;
                }
                point++;
            }
        }

        // 흐린 영역에 블럭이 위치하는지 찾아본다
        for(int col = 0; col <= 1; col++) {
            boolean flag = false;
            for(int row = 0; row < blue.length; row++) {
                if(blue[row][col]) {
                    flag = true;
                    break;
                }
            }

            // 해당 열에 블럭이 존재한다면
            // 마지막 줄을 제거하고 모든 블럭을 오른쪽으로 한 줄씩 민다
            if(flag) {
                for(int prevCol = blue[0].length - 1; prevCol > 0; prevCol--) {
                    for(int row = 0; row < blue.length; row++)
                        blue[row][prevCol] = blue[row][prevCol - 1];
                }

                for(int row = 0; row < blue.length; row++)
                    blue[row][col] = false;
            }
        }
    }

    static class Block {
        int x, y, blockType;

        public Block(int x, int y, int blockType) {
            this.x = x;
            this.y = y;
            this.blockType = blockType;
        }
    }

    public static void main(String[] args) {
        input();
        solution();
    }

    static class Reader {
        BufferedReader br;
        StringTokenizer st;

        public Reader() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        String next() {
            while(st == null || !st.hasMoreElements()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            return st.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }
    }
}

4.  접근

  • 주어진 블록들을 표현하기 위해 Block 클래스를 정의합니다.
    • 주어진 블록을 놓는 위치의 행의 좌표를 나타내는 x, 열의 좌표를 나타내는 y, 해당 블록의 타입을 나타내는 blockType을 멤버 변수로 갖습니다.
  • 파란색 보드와 초록색 보드를 각각 blue라는 2차원 배열과 green이라는 2차원 배열로 나타냅니다.
    • 블록이 놓여있는 칸은 true, 놓여있지 않은 칸은 false 값을 갖습니다.
  • 주어진 블록들을 순서대로 돌면서 각 턴을 진행합니다.
    • 각 턴은 파란색 보드로 블록이 움직이는 경우와 초록색 보드로 블록이 움직이는 경우로 나뉩니다.
    • 초록색 보드로 움직이는 경우를 먼저 살펴보겠습니다.
      • 만약 해당 블록 타입이 1 또는 3일 경우는 한 열에 블록조각이 놓여있기 때문에 초록색 보드의 0번 행부터 시작하여 블록이 있는 곳 혹은 바닥까지 한 칸씩 내립니다.
        • 만약 블록 타입이 1이라면 블록이 있는 곳 바로 전 혹은 바닥에 해당 블록을 놓습니다.
        • 만약 블록 타입이 3이라면 블록이 있는 곳 바로 전과 그 전 혹은 바닥과 바닥 바로 전에 블록조각을 놓습니다.
      • 만약 해당 블록 타입이 2라면 두 개의 열을 차지하기 때문에 두 열에 대해서 0번 행부터 시작하여 블록이 있는 곳 혹은 바닥까지 한 칸씩 내립니다.
        • 바닥에 혹은 블록이 있는 곳 바로 전 행에 블록조각을 놓는데, 해당 위치와 바로 오른쪽 위치에 놓습니다.
      • 이후에 한 행이 모두 블록으로 채워져있는지 확인합니다.
        • 만약 모두 블록으로 채워져있다면 해당 행의 모든 블록을 지우고 위에 있는 블록들을 한 칸씩 아래로 내립니다.
      • 흐린 영역에 블록이 위치해있는지 확인합니다.
        • 만약 흐린 영역에 블록이 존재한다면 마지막 줄을 제거하고 위의 모든 블록들을 아래로 한 칸씩 내립니다.
    • 파란색 보드로 움직이는 경우는 초록색 경우와 같지만 행을 열로, 열을 행으로 변경하면 됩니다.
    • 위 작업을 주어진 모든 블록에 순서대로 실행합니다.
  • 모든 블록에 대해 위 작업들을 수행했다면 파란색 보드와 초록색 보드에 있는 블록들의 개수를 세고 이를 출력합니다.
profile
자바, 웹 개발을 열심히 공부하고 있습니다!

0개의 댓글