https://www.acmicpc.net/problem/1074
1074번: Z
한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다. N > 1인 경우, 배열을
www.acmicpc.net
코드설명
분할정복 문제입니다.
처음에 단순히 분할정복을 사용햇다가 시간초과가 걸렸습니다.
문제 조건에 시간제한으로 0.5초가 설정되어있어, map의 모든 구간을 검사한다면 시간초과가 납니다.
즉, 1, 2, 3, 4 사분면 중에 어디 범위에 속해있는지 체크하여 해당 사분면 범위에 속해있다면 그 부분만 재귀를 돌리면 됩니다.
범위처리 코드는 아래와 같습니다.
각 중간점을 기준으로 해당 중간점보다 작다면 좌측, 크다면 우측으로 처리합니다. (상하도 동일합니다.)
if( R < startR + nSize && C < startC + nSize) { //1사분면에 R,C 가 존재한다면. divideConquer(startR, startC, nSize); } if( R < startR + nSize && C >= startC + nSize ) { // 2사분면에 R,C 가 존재한다면 answer += (size * size) / 4; divideConquer(startR, startC + nSize, nSize); } if( R >= startR + nSize && C < startC + nSize) { answer += ((size*size) / 4 ) * 2; divideConquer(startR + nSize, startC, nSize); } if( R >= startR + nSize && C >= startC + nSize) { answer += ((size * size) / 4 ) * 3; divideConquer(startR + nSize, startC + nSize, nSize); }
코드
범위처리를 통해 불필요한 재귀 생략.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int N, R, C; 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()); R = Integer.parseInt(st.nextToken()); C = Integer.parseInt(st.nextToken()); divideConquer(0, 0, (int) Math.pow(2, N)); } public static void divideConquer(int startR, int startC, int size) { if(size == 1) { System.out.println(answer); return ; } int nSize = size / 2; if( R < startR + nSize && C < startC + nSize) { //1사분면에 R,C 가 존재한다면. divideConquer(startR, startC, nSize); } if( R < startR + nSize && C >= startC + nSize ) { // 2사분면에 R,C 가 존재한다면 answer += (size * size) / 4; divideConquer(startR, startC + nSize, nSize); } if( R >= startR + nSize && C < startC + nSize) { answer += ((size*size) / 4 ) * 2; divideConquer(startR + nSize, startC, nSize); } if( R >= startR + nSize && C >= startC + nSize) { answer += ((size * size) / 4 ) * 3; divideConquer(startR + nSize, startC + nSize, nSize); } } }
시간초과 나는 코드, 일반 분할정복사용
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class Main { public static int N, r, c; 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()); r = Integer.parseInt(st.nextToken()); c = Integer.parseInt(st.nextToken()); divideConquer(0, 0, (int) Math.pow(2, N)); } public static void divideConquer(int tempR, int tempC, int size) { if(size == 1 && tempR == r && tempC== c) { System.out.println(answer); System.exit(0); return ; } if(size == 1 ) { // size가 1일떄 한개를 검사하는것이므로 반드시 더하고 종료. answer += 1; return ; } // answer += 1; 여기에 처리하면 다 더해지지 않음. int nSize = size / 2; divideConquer(tempR, tempC, nSize); divideConquer(tempR, tempC + nSize, nSize); //여기서 재귀 호출시 Z 방향으로 작동되게 재귀호출합니다. divideConquer(tempR + nSize, tempC, nSize); divideConquer(tempR + nSize, tempC + nSize, nSize); } }
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 4779 칸토어 집합 - 분할정복 + 재귀 JAVA (0) | 2023.10.06 |
---|---|
[백준] 2447 별 찍기 - 분할정복 + 재귀 JAVA (0) | 2023.10.04 |
[백준] 쿼드트리 1992 - 분할정복(DivideAndConquer) JAVA (0) | 2023.10.02 |
[백준] 222-풀링 17829 - 분할정복 JAVA (0) | 2023.10.01 |
[백준] 2630 색종이 만들기 - 분할정복 JAVA (0) | 2023.09.30 |