ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SWEA] 17136번 : 색종이 붙이기
    BOJ 2024. 5. 18. 23:47

    진짜 참 어렵다....

    왜 이걸 푼다고 하필 오늘...

    결국 답을 봤고,,,이해하고 나서 내 코드로 바꿔보려고 했는데 실-패 ㅠㅠ

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

     

    결국 풀이를 생각해내지 못해서, 아래 블로그를 참고했다!!

    https://steady-coding.tistory.com/43

     

    [BOJ] 백준 17136번 : 색종이 붙이기 (JAVA)

     

    steady-coding.tistory.com

     

     

     

    이건 어떻게 풀었냐?!

    x, y를 하나씩 증가 시키면서 p 배열에 사용할 수 있는 종이 개수를 담아둔다.

    첫번째. 붙일 수 있는지 체크하고

    두번째. 붙이는 게 가능하다면 붙이면 된다.

    만약에 붙일 수 없으면 그냥 함수를 나와버린다.

    여기서 dfs 를 돌려서 끝점에 도달하면 그때 최소값을 구하고, 

    static void solve(int x, int y, int depth) {
            // 겹쳐도 안 된다.
            // 0 이 적힌 칸에는 색종이 없어야 한다.
    
            // 맨 끝점
            if(x>=9 && y>9) {
                ans = Math.min(ans, depth);
                return;
            }
    
            // 가지 치기
            // 최소 구해야 함
            // 근데 ans 가 depth 보다 커지면 탐색 X
            if(ans<=depth) return;
    
            // 아래 줄로 이동
            if(y>9) {
                solve(x+1, 0, depth);
                return;
            }
    
            if(map[x][y]==1) {
                for(int i=5;i>=1;i--) {
                    // 1. check (붙일 수 있는지)
                    if(p[i]>0 && check(x, y, i)) {
                        // 2. attach (가능 하면 붙여)
                        attach(x, y, i, 0); // 색종이 붙이고
                        p[i]--;
                        solve(x, y+1, depth+1);
                        attach(x, y, i, 1); // 다시 떼
                        p[i]++;
                    }
                }
            }
            else {
                // 오른쪽 으로 이동
                solve(x, y+1, depth);
            }
    
        }

     

    현재 좌표를 기준으로 범위 체크와 1인지 아닌지를 확인해준다. 이때 size에 맞게 1이 다 있으면 색종이를 붙일 수 있으니까 true를 리턴한다.

    // 1. check
        static boolean check(int x, int y, int s) {
            for(int i=x;i<x+s;i++) {
                for(int j=y;j<y+s;j++) {
                    // 범위를 벗어 나면
                    if(i<0 || i>=10 || j<0 || j>=10) return false;
                    // 범위에 있어도 1이 아니면
                    if(map[i][j]!=1) return false;
                }
            }
            return true;
        }

     

    그리고 범위 체크를 위에서 했으면 그냥 붙여주기만 하면 된다. 

    // 2. attach
        static void attach(int x, int y, int s, int val) {
            for(int i=x;i<x+s;i++) {
                for(int j=y;j<y+s;j++) {
                    map[i][j] = val;
                }
            }
        }

    [전체코드]

    import java.io.*;
    import java.util.*;
    
    class Main {
    
    //    static int n;
        static int map[][], ans;
        static int p[] = {0, 5, 5, 5, 5, 5};
    
        public static void main(String[] args) throws Exception {
    
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st;
    
    //        int T = Integer.parseInt(br.readLine());
    
    //        for(int tc=1;tc<=T;tc++) {
    
                map = new int[10][10];
                for(int i=0;i<10;i++) {
                    st = new StringTokenizer(br.readLine());
                    for(int j=0;j<10;j++) {
                        map[i][j] = Integer.parseInt(st.nextToken());
                    }
                }
    
                // 1
                // 2 * 2 = 4
                // 3 * 3 = 9
                // 4 * 4 = 16
                // 5 * 5 = 25
                ans = Integer.MAX_VALUE;
                solve(0, 0, 0);
                System.out.println(ans==Integer.MAX_VALUE ? -1 : ans);
    
                br.close();
    //        }
    
        }
    
        static void solve(int x, int y, int depth) {
            // 겹쳐도 안 된다.
            // 0 이 적힌 칸에는 색종이 없어야 한다.
    
            // 맨 끝점
            if(x>=9 && y>9) {
                ans = Math.min(ans, depth);
                return;
            }
    
            // 가지 치기
            // 최소 구해야 함
            // 근데 ans 가 depth 보다 커지면 탐색 X
            if(ans<=depth) return;
    
            // 아래 줄로 이동
            if(y>9) {
                solve(x+1, 0, depth);
                return;
            }
    
            if(map[x][y]==1) {
                for(int i=5;i>=1;i--) {
                    // 1. check (붙일 수 있는지)
                    if(p[i]>0 && check(x, y, i)) {
                        // 2. attach (가능 하면 붙여)
                        attach(x, y, i, 0); // 색종이 붙이고
                        p[i]--;
                        solve(x, y+1, depth+1);
                        attach(x, y, i, 1); // 다시 떼
                        p[i]++;
                    }
                }
            }
            else {
                // 오른쪽 으로 이동
                solve(x, y+1, depth);
            }
    
        }
    
        // 1. check
        static boolean check(int x, int y, int s) {
            for(int i=x;i<x+s;i++) {
                for(int j=y;j<y+s;j++) {
                    // 범위를 벗어 나면
                    if(i<0 || i>=10 || j<0 || j>=10) return false;
                    // 범위에 있어도 1이 아니면
                    if(map[i][j]!=1) return false;
                }
            }
            return true;
        }
    
        // 2. attach
        static void attach(int x, int y, int s, int val) {
            for(int i=x;i<x+s;i++) {
                for(int j=y;j<y+s;j++) {
                    map[i][j] = val;
                }
            }
        }
    
    }

     

    이건 내가 바꿔보려고 시도한 코드...굳이 y를 증가시키는걸 재귀로 돌렸어야하나? 싶어서

    for문으로 했는데 이러면 return 되면서 백트래킹에 문제가 생긴다...쩝...

    
    
    
    import java.io.*;
    import java.util.*;
    
    class Main {
    
        //    static int n;
        static int map[][], ans;
        static boolean flag=true;
        static int p[] = {0, 5, 5, 5, 5, 5};
    
        public static void main(String[] args) throws Exception {
    
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st;
    
    //        int T = Integer.parseInt(br.readLine());
    
    //        for(int tc=1;tc<=T;tc++) {
    
            map = new int[10][10];
            for(int i=0;i<10;i++) {
                st = new StringTokenizer(br.readLine());
                for(int j=0;j<10;j++) {
                    map[i][j] = Integer.parseInt(st.nextToken());
                }
            }
    
            // 1
            // 2 * 2 = 4
            // 3 * 3 = 9
            // 4 * 4 = 16
            // 5 * 5 = 25
            ans = Integer.MAX_VALUE;
            solve(0, 0,0);
            System.out.println(ans==Integer.MAX_VALUE ? -1 : ans);
    
            br.close();
    //        }
    
        }
    
        static void solve(int x, int y, int depth) {
            if(ans<=depth) return;
    
            if(x>9) {
                ans = Math.min(ans, depth);
                flag = false;
                return;
            }
    
            for(int j=y;j<10;j++) {
                if(map[x][j]==1) {
                    for (int i = 5; i >= 1; i--) {
                        if (p[i] > 0 && check(x, j, i)) {
                            attach(x, j, i, 0);
                            p[i]--;
                            solve(x, j+1, depth + 1);
                            p[i]++;
                            attach(x, j, i, 1);
                        }
                    }
                }
            }
    
            if(flag) solve(x+1, 0, depth);
    
        }
    
        static boolean check(int x, int y, int val) {
            for(int i=x;i<x+val;i++) {
                for(int j=y;j<y+val;j++) {
                    // 범위 벗어남
                    if(i<0 || i>=10 || j<0 || j>=10) return false;
                    // 1이 아니면
                    if(map[i][j]!=1) return false;
                }
            }
            return true;
        }
    
        static void attach(int x, int y, int s, int val) {
            for(int i=x;i<x+s;i++) {
                for(int j=y;j<y+s;j++) {
                    map[i][j]=val;
                }
            }
        }
    
    }

    'BOJ' 카테고리의 다른 글

    [BOJ] 2468번 : 안정영역 (JAVA)  (0) 2024.12.10
    [BOJ] 1991번 : 트리 순회  (1) 2024.06.08
    [BOJ] 2644번 : 촌수계산  (0) 2024.05.12
    [Java] 1389번 : 케빈 베이컨의 6단계 법칙  (1) 2024.02.12
    [Java] 17471번 : 게리맨더링  (1) 2024.02.02
Designed by Tistory.