https://www.acmicpc.net/problem/1992
1992번: 쿼드트리
첫째 줄에는 영상의 크기를 나타내는 숫자 N 이 주어진다. N 은 언제나 2의 제곱수로 주어지며, 1 ≤ N ≤ 64의 범위를 가진다. 두 번째 줄부터는 길이 N의 문자열이 N개 들어온다. 각 문자열은 0 또
www.acmicpc.net
코드설명
분할 정복 문제입니다.
문제로직입니다.
1. (0, 0)에서 N 을 가지고서 분할정복 재귀가 실행됩니다.
2. map[N][N] 을 -> 4가지 로 나누어서 각 4분면에 해당하는 값들이 하나의 숫자로 이루어질때까지 재귀가 실행됩니다. ( 이떄 size가 1이면 무조건 하나의 숫자로 이루어지므로, size==1 인경우 따로 처리필요는 없습니다. )
3. 문제에서 "(" 와 ")"의 경우 처리를 하는경우, 재귀의 시작이 이루어질경우 새로운 칸이 분할되는것으로 생각하면 됩니다. 새로운 재귀가 실행될때 "(" 를 삽입하고 해당 레벨의 재귀가 끝날떄 다시 ")" 로 닫아줍니다.
이번 코드에서 Character.toString(Character 값) 에 대해 처음 알았습니다.
항상 String.valueOf(Character값)으로 처리했었는데.. 훨씬 직관적으로 작성할 수 있었습니다.
코드
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int N, M; public static char[][] map; public static int answer = 0; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); map = new char[N][N]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); map[i] = st.nextToken().toCharArray(); } divideConquer(0, 0, N); System.out.println(sb.toString()); } public static void divideConquer(int r, int c, int size) { //만약 검사한 구간이 하나의 숫자로 이루어져있다면, 압축성공 ( size == 1 인경우를 따로 고려안해도 size가 1 이면 무조건 한가지의 색으로 이루어져있음 ) if(checkMap(r, c, size) == true) { sb.append(map[r][c]); return ; } sb.append("("); int nSize = size / 2; divideConquer(r, c, nSize); divideConquer(r, c + nSize, nSize); divideConquer(r + nSize, c, nSize); divideConquer(r + nSize, c + nSize, nSize); sb.append(")"); } public static boolean checkMap(int r, int c, int size) { char standard = map[r][c]; for(int i=r; i<r + size;i++) { for(int j=c;j<c + size;j++) { if(map[i][j] != standard) { return false; } } } return true; } }
기저사례로 size == 1로 하고, return 처리하여 완료합니다.
그래야만, 한개로 이루어졌을 경우 isCompressable은 항상 true이기에 같은 숫자가 두번 들어가지 않습니다.
package algorhythm; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int C, N, M; public static int INF = 0; public static char[][] matric; public static int answer = 0; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); matric = new char[N][N]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); matric[i] = st.nextToken().toCharArray(); } compress(matric, 0, 0, N); System.out.println(sb.toString()); } public static void compress(char[][] A, int r, int c, int size) { //기저 사례 1 : size가 1이라면 더이상 불가합니다 if(size == 1) { sb.append(A[r][c]); return ; } //만약 (r, c) ~ (r + size, c + size) 까지의 사각형이 압축이 가능하다면, if(isCompressable(A, r, c, size) == true) { sb.append(A[r][c]); return ; } //만약 압축이 불가하다면, 재귀적 압축이 시작됩니다. sb.append("("); int halfSize = size / 2; compress(A, r, c, halfSize); compress(A, r, c + halfSize, halfSize); compress(A, r + halfSize, c, halfSize); compress(A, r + halfSize, c + halfSize, halfSize); sb.append(")"); } public static boolean isCompressable(char[][] A, int r, int c, int size) { char startNum = A[r][c]; for(int i=r;i<r + size;i++) { for(int j=c;j<c + size;j++) { if(startNum != A[i][j] ) { return false; } } } return true; } }
반환형식을 String으로 하여 각 부분문제의 반환값을 받아서 처리합니다.
package algorhythm; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int C, N, M; public static int INF = 0; public static char[][] matric; public static int answer = 0; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); matric = new char[N][N]; for(int i=0;i<N;i++) { st = new StringTokenizer(br.readLine()); matric[i] = st.nextToken().toCharArray(); } System.out.println(compress(matric, 0, 0, N)); // System.out.println(sb.toString()); } public static String compress(char[][] A, int r, int c, int size) { //기저 사례 1 : size가 1이라면 더이상 불가합니다 if(size == 1) { return Character.toString(A[r][c]); } //만약 (r, c) ~ (r + size, c + size) 까지의 사각형이 압축이 가능하다면, if(isCompressable(A, r, c, size) == true) { return Character.toString(A[r][c]); } //만약 압축이 불가하다면, 재귀적 압축이 시작됩니다. int halfSize = size / 2; String leftTop = compress(A, r, c, halfSize); String rightTop = compress(A, r, c + halfSize, halfSize); String leftBottom = compress(A, r + halfSize, c, halfSize); String rightBottom = compress(A, r + halfSize, c + halfSize, halfSize); return "(" + leftTop + rightTop + leftBottom + rightBottom +")"; } public static boolean isCompressable(char[][] A, int r, int c, int size) { char startNum = A[r][c]; for(int i=r;i<r + size;i++) { for(int j=c;j<c + size;j++) { if(startNum != A[i][j] ) { return false; } } } return true; } }
추가로 만약 쿼드트리를 Decompress한다면 어떻게 될까?
입력 1 8 ((110(0101))(0010)1(0001)) 결과 1 11110000 11110000 00011100 00011100 11110000 11110000 11110011 11110011
아래의 코드의 핵심은,
'(' 를 발견한다면, 네 개의 사분면을 모두 돌아야 한다는 것 이다.
만약 해당 칸이 '[0, 1]'라면, 현재 재귀 레벨의 r, c, size를 가지고서 색칠하면 된다.
package algorhythm; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int C, N, M; public static int INF = 0, index; public static char[][] matrix; public static int answer = 0; public static StringBuilder sb = new StringBuilder(); public static void main(String[] args) throws IOException{ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(br.readLine()); N = Integer.parseInt(st.nextToken()); matrix = new char[N][N]; String compressedString = br.readLine(); index = 0; decompress(compressedString, 0, 0, N); printMatrix(matrix); } public static void decompress(String s, int r, int c, int size) { if (size == 1) { matrix[r][c] = s.charAt(index++); return; } if (s.charAt(index) == '(') { index++; int halfSize = size / 2; decompress(s, r, c, halfSize); decompress(s, r, c + halfSize, halfSize); decompress(s, r + halfSize, c, halfSize); decompress(s, r + halfSize, c + halfSize, halfSize); index++; // ')' 로 닫아주므로 인덱스를 증가시키며 넘어갑니다. } else { fillMatrix(r, c, size, s.charAt(index++)); return ; } } public static void fillMatrix(int r, int c, int size, char value) { for (int i = r; i < r + size; i++) { for (int j = c; j < c + size; j++) { matrix[i][j] = value; } } } public static void printMatrix(char[][] matrix) { for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { System.out.print(matrix[i][j]); } System.out.println(); } } }
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 2447 별 찍기 - 분할정복 + 재귀 JAVA (0) | 2023.10.04 |
---|---|
[백준] Z 1074 - 분할정복 JAVA (0) | 2023.10.03 |
[백준] 222-풀링 17829 - 분할정복 JAVA (0) | 2023.10.01 |
[백준] 2630 색종이 만들기 - 분할정복 JAVA (0) | 2023.09.30 |
[백준] 9996 한국이 그리울 땐 서버에 접속하지 - 문자열(String) + 정규표현식(Regular Expression) + 동적계획법(DP, Dynamic Programming) JAVA (0) | 2023.09.28 |