Problem Solving/Baekjoon

[백준/JAVA] 18808 - 스티커 붙이기

jihyeon99 2024. 5. 22. 16:43

문제 정보

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

 

문제

 

코드

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int n = Integer.parseInt(st.nextToken()); // 전체 맵 세로 길이
        int m = Integer.parseInt(st.nextToken()); // 전체 맵 가로 길이
        int k = Integer.parseInt(st.nextToken()); // 스티커의 개수
        boolean[][] isExist = new boolean[n][m]; // 해당 칸에 스티커 존재 여부

        Queue<List<int[]>> queue = new ArrayDeque<>(); // 스티커의 정보를 담고있는 큐

        // 스티커들의 좌표 입력받기
        for(int i=0; i<k; i++) {
            st = new StringTokenizer(br.readLine());
            int rsize = Integer.parseInt(st.nextToken()); // 스티커의 세로 길이
            int csize = Integer.parseInt(st.nextToken()); // 스티커의 가로 길이

            List<int[]> list = new ArrayList<>(); // 현재 스티커의 정보 담는 리스트

            for(int r=0; r<rsize; r++) {
                st = new StringTokenizer(br.readLine());
                for(int c=0; c<csize; c++) {
                    int cur = Integer.parseInt(st.nextToken());
                    // 스티커가 존재한다면, 스티커 정보 넣음
                    if(cur == 1) {
                        list.add(new int[]{r,c,rsize,csize}); // x좌표, y좌표, 세로길이, 가로길이
                    }
                }
            }

            queue.add(list);
        }

        // 스티커 붙히기
        for(int i=0; i<k; i++) {
            List<int[]> sticker = queue.poll(); // 현재 스티커의 정보

            for(int j=0; j<4; j++) {
                // 스티커를 붙일 수 있는 좌표 찾음
                int[] pos = findPos(n, m, isExist, sticker);

                // 스티커를 붙일 수 있는 경우
                if(pos[0] >= 0 && pos[1] >= 0) {
                    // 스티커 붙힘
                    isExist = attachSticker(n, m, isExist, sticker, pos[0], pos[1]);
                    break;
                }

                // 스티커를 붙일 수 없는 경우, 스티커를 시계방향으로 90도 회전시킴
                rotateStiker(n, m, sticker);
            }

        }

        // 스티커 붙은 칸 수 출력
        int cnt = 0;
        for(int r=0; r<n; r++) {
            for(int c=0; c<m; c++) {
                if(isExist[r][c]) cnt++;
            }
        }

        System.out.println(cnt);
    }

    static void rotateStiker(int n, int m, List<int[]> sticker) {
        for(int i=0; i<sticker.size(); i++) {
            int[] cur = sticker.get(i);
            int curx = cur[0]; // 현재 스티커 조각의 상대 x좌표
            int cury = cur[1]; // 현재 스티커 조각의 상대 y좌표

            int rlen = cur[2]; // 현재 세로 길이
            int clen = cur[3]; // 현재 가로 길이

            // 좌표는 (r,c) => (c, (n-1)-r)이되고, 세로와 가로 길이도 바뀜
            sticker.set(i, new int[]{cury, (rlen-1)-curx, clen, rlen});
        }
    }

    static boolean[][] attachSticker(int n, int m, boolean[][] isExsit, List<int[]> sticker, int sx, int sy) {
        // 원본 배열 복사
        boolean[][] newMap = new boolean[n][m];
        for(int i=0; i<n; i++) {
            newMap[i] = Arrays.copyOf(isExsit[i], m);
        }

        for(int i=0; i<sticker.size(); i++) {
            int[] cur = sticker.get(i);
            int curx = sx + cur[0]; // 현재 스티커 조각의 실제 x좌표
            int cury = sy + cur[1]; // 현재 스티커 조각의 실제 y좌표

            // 현재 스티커 조각을 붙힘
            newMap[curx][cury] = true;
        }

        return newMap;
    }

    static int[] findPos(int n, int m, boolean[][] isExist, List<int[]> sticker) {

        // 좌상단부터 스티커를 붙힐 수 있는 영역 찾음
        for(int r=0; r<n; r++) {
            for(int c=0; c<m; c++) {
                // 모든 스티커 조각 붙힐 수 있는 경우, 해당 위치를 반환
                if(canAttach(n, m, isExist, sticker, r, c)) {
                    return new int[]{r, c};
                }
            }
        }

        return new int[] {-1, -1};
    }

    static boolean canAttach(int n , int m, boolean[][] isExist, List<int[]> sticker, int sx, int sy) {

        for(int i=0; i<sticker.size(); i++) {
            int[] cur = sticker.get(i);
            int curx = sx + cur[0]; // 현재 스티커 조각의 실제 x좌표
            int cury = sy + cur[1]; // 현재 스티커 조각의 실제 y좌표

            // 노트북 벗어나면 스티커 붙일 수 없음
            if(curx<0 || curx>=n || cury<0 || cury>=m) {
                return false;
            }

            // 다른 스티커와 겹치면, 스티커 붙일 수 없음
            if(isExist[curx][cury]) {
                return false;
            }
        }

        return true;
    }
}