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();
        }
    }
	
}

+ Recent posts