import java.io.*;
import java.util.StringTokenizer;
public class Main {
static int answer;
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))
) {
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
find((int) Math.pow(2, N), r, c);
bw.write(answer + "\n");
bw.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void find(int size, int r, int c) {
if(size == 1)
return;
if(r < size/2 && c < size/2) {
find(size/2, r, c);
}
else if(r < size/2 && c >= size/2) {
answer += size * size / 4;
find(size/2, r, c - size/2);
}
else if(r >= size/2 && c < size/2) {
answer += (size * size / 4) * 2;
find(size/2, r - size/2, c);
}
else {
answer += (size * size / 4) * 3;
find(size/2, r - size/2, c - size/2);
}
}
}
우선 찾고자하는 좌표 (r,c)의 위치가 어디에 있는지를 파악해야한다.
주어진 2차원 배열을 4등분 해서 찾는다고 하는데 이걸 사분면으로 나눠서 생각을 하게 되면 왼쪽 위 부터 순서대로 1,2,3,4 사분면이 되는데...
(이걸 언제 배웠었더라 사분면...)
- r과 c가 1사분면에 속한다면, 앞에서 아무데도 방문하지 않았으므로 count를 그냥 두고, find메소드에 현재 size의 절반, 1사분면에서의 r,c 상대위치 r,c를 넘겨준다.
- r과 c가 2사분면에 속한다면, 앞에서 1사분면을 방문해야하므로 count에 (size*size)/4를 더한다.
(한 사분면의 크기: 전체 배열 크기의 4등분)
find메소드에 현재 size의 절반, 2사분면에서의 r,c 상대위치 r, c-size/2를 넘겨준다.
- r과 c가 3사분면에 속한다면, 앞에서 1,2 사분면을 방문해야하므로 count에 (sizesize)/4 2를 더한다.
find메소드에 현재 size의 절반, 3사분면에서의 r,c 상대위치 r-size/2, c를 넘겨준다.
- r과 c가 4사분면에 속한다면, 앞에서 1,2,3 사분면을 방문해야하므로 count에 (sizesize)/4 3를 더한다.
find메소드에 현재 size의 절반, 4사분면에서의 r,c 상대위치 r-size/2, c-size/2를 넘겨준다.
- 위를 반복하다가 size가 1이 되면 재귀를 끝낸다.
지혜로운 개발로그님의 블로그에서 본 해설이다.
각 사분면의 위치에서 다시 또 4등분을 해서 좌표의 값을 찾아야 하기 때문에 이렇게 문제를 푸는 것.
글을 읽으면 읽을 수록 좀 헷갈리긴 한다 ㅋㅋㅋ... ㅎㅎ;;;
계속해서 4등분을 해서 값을 찾는 과정이라는 것을 이해하자!!
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))
) {
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
int mapSize = (int) Math.pow(2, N);
int[][] maps = new int[mapSize][mapSize];
fillMaps(maps, N, 0 , 0);
bw.write(maps[r][c] + "\n");
bw.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
static int mapValue = 0;
private static void fillMaps(int[][] maps, int N, int x, int y) {
if (N == 0) return;
//2차원 배열을 2^(N-1) x 2^(N-1)로 4등분 한 후 방문
int size = (int) Math.pow(2, N - 1);
if (N == 1) {
maps[x][y] = mapValue++;
maps[x][y + 1] = mapValue++;
maps[x + 1][y] = mapValue++;
maps[x + 1][y + 1] = mapValue++;
}
// 좌표가 (0,0) -> (0,2^(N-1)) -> (2^(N-1),0) -> (2^(N-1),2^(N-1)) 순으로 이동
fillMaps(maps, N - 1, x, y);
fillMaps(maps, N - 1, x, y + size);
fillMaps(maps, N - 1, x + size, y);
fillMaps(maps, N - 1, x + size, y + size);
}
}
내가 가장 처음 작성한 코드이다.
진짜로 2차원 배열을 다 Z 이동 방식으로 다 구해버리고 문제에서 요구하는 (r,c)의 값을 출력...!!
당연히 내 컴퓨터에서는 잘 돌아간다. 아니 누구라도 아주 잘 돌아가는 코드일 것이다.
문제는...!!! 요구사항을 만족하지 못한다는 것.

아아... 장렬하게 전사해버린 메모리...
아 배열로 풀 생각에 사로잡혀 가지고.. 재귀도 했고 한데 도대체 어떻게 해야하지???? 하다가 결국 정답을 찾아봤다 ㅠㅠ
노가다 말고 주어진 좌표가 4등분 이후에 어디에 위치하는지 파악해서 계속 찾는 방법!! 너무 좋은 것 같다!!