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

+ Recent posts