[원리]
분할정복은 문제를 나눌 수 없을 때까지 나누어 병합하며 문제를 해결하는 방식
[분석]
이 문제를 풀수 있는 방법은 아래와 같이 2가지다.
-방법 1
현재 범위의 종이가 색깔을 본다.
1) white인가 -> whiteCount ++
2) black인가 -> blackCount ++
3) 둘다 아닌가 -> 분할해서 찾아본다.
사실 분할 정복알고리즘으로 대표적인 알고리즘은 Merge Sort인데, 이 경우 정말 최소단위까지 내려가 병합하여 정렬하지만, 내 소스의 경우 Merge Sort라고 하면 이미 정렬되어있는지 먼저 검사하고 분할하여 탐색한다고 볼 수 있다.
-방법 2
1) 일단 4분할을 한다.
2) 4분할 하여 반환된 색깔이 모두 같은 색인가?
2-True) 색을 반환한다.
2-False) 반환된 색깔들은 더이상 다른 곳에 병합될 수 없으므로 각 색깔에 대해 카운트한다.
방법2의경우 미리 검사하지 않고 정말 최소단위까지 분할 후 병합하며 해답을 찾아낸다.
[구현 | 방법 1]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import java.util.Scanner; /** * @title 색종이 만들기 * @problem http://jungol.co.kr/bbs/board.php?bo_table=pbank&wr_id=614&sca=3060 * @author Jinseoung Lee * @type Divide And Conquer */ public class ColorPaper { public static Scanner sc; public static final boolean BLACK = true, WHITE = false; public static boolean[][] map; public static int N, whiteCount, blackCount; public static void main(String[] args) { sc = new Scanner(System.in); N = sc.nextInt(); map = new boolean[N][N]; /*********************************************************************************** * 입력 ***********************************************************************************/ for(int i = 0; i < N; i++){ for(int j = 0 ; j < N ; j++){ map[i][j] = sc.nextInt() == 1; } } /*********************************************************************************** * 탐색 ***********************************************************************************/ search(0,0,N); /*********************************************************************************** * 출력 ***********************************************************************************/ System.out.println(whiteCount); System.out.println(blackCount); } /** * 분할정복을 제귀적으로 탐색함 * * @param x | 시작 x 좌표 * @param y | 시작 y 좌표 * @param range | 검색 범위 */ public static void search (int x, int y, int range){ // 이 영역이 BLACK이나 WHITE도 아닐 때 if(!is(ColorPaper.BLACK, x, y, range) && !is(ColorPaper.WHITE, x, y, range) ){ int increase = range/2; search(x, y, increase); search(x+increase, y, increase); search(x, y+increase, increase); search(x+increase, y+increase, increase); } } /** * 이 영역이 white인지 black인지 아니면 mixed 인지 검색 * * @param TYPE | Main.WHITE, Main.BLACK 을통해 이것이 화이트 또는 블랙인지를 찾을 수 있음 * @param x | 시작 X좌표 * @param y | 시작 Y좌표 * @param range | 검색 범위 * @return | false, true에 따라서 맞는지 아닌지에 대해서 반환 * * @example * is(Main.BLACK, 0, 0, N) -> 0, 0부터 N만큼 체크하며 BLACK인지를 판단한다. */ public static boolean is (boolean TYPE, int x, int y, int range){ for(int i = y; i < y+range; i++){ for(int j = x; j < x+range; j++){ if(map[i][j] != TYPE) return false; } } if(TYPE == BLACK) blackCount++; else if(TYPE == WHITE) whiteCount++; return true; } } | cs |
[구현 | 방법 2 - 재귀 | 분할 -> 병합 순으로 진행되며 병합하는 과정에서 해답을 도출해낸다. ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | public class ColorPaperReal { public static Scanner sc; public static int[] counts = new int[3]; public static int[][] map; public static int N; public static void main(String[] args) { sc = new Scanner(System.in); N = sc.nextInt(); map = new int[N][N]; /*********************************************************************************** * 입력 ***********************************************************************************/ for(int i = 0; i < N; i++){ for(int j = 0 ; j < N ; j++){ map[i][j] = sc.nextInt(); } } /*********************************************************************************** * 탐색 ***********************************************************************************/ counts[search(0,0,N)]++; /*********************************************************************************** * 출력 ***********************************************************************************/ System.out.println(counts[0]); System.out.println(counts[1]); } public static int search ( int x, int y, int range){ if(range == 1 ) return map[y][x]; int[] results = new int[4]; int increase = range/2; results[0] = search(x, y, increase); results[1] = search(x+increase, y, increase); results[2] = search(x, y+increase, increase); results[3] = search(x+increase, y+increase, increase); if(!isAllEquals(results)){ for(int i = 0 ; i < results.length; i ++) counts[results[i]]++; return 2; } else { return results[0]; } } public static boolean isAllEquals(int[] results){ int target = results[0]; for(int i = 1; i < results.length; i++){ if(target != results[i]) return false; } return true; } } | cs |
[구현 | 방법 2 - 포문 구현 | 분할하는 과정이 없고 병합하며 해답을 도출해 낸다. ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | public class ColorPaperFast { public static Scanner sc; public static int[] counts = new int[3]; public static byte[][] map; public static int N; public static void main(String[] args) { sc = new Scanner(System.in); N = sc.nextInt(); map = new byte[N][N]; /*********************************************************************************** * 입력 ***********************************************************************************/ for(int i = 0; i < N; i++){ for(int j = 0 ; j < N ; j++){ map[i][j] = (byte)sc.nextInt(); } } /*********************************************************************************** * 탐색 ***********************************************************************************/ for(int i = N; i > 1; i/=2 ){ int mixedCount = 0; for(int y = 0; y < i; y += 2){ for(int x = 0; x < i; x += 2){ if(!(map[y][x] == map[y][x+1] && map[y][x+1] == map[y+1][x] && map[y+1][x] == map[y+1][x+1] )){ counts[map[y][x]]++; counts[map[y][x+1]]++; counts[map[y+1][x]]++; counts[map[y+1][x+1]]++; map[y/2][x/2] = 2; mixedCount++; } else { map[y/2][x/2] = map[y][x]; } } } if(mixedCount == (N*N)/4 ) break; } /*********************************************************************************** * 출력 ***********************************************************************************/ System.out.println(counts[0]); System.out.println(counts[1]); } } | cs |