1. 문제
문제
한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다. 예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

N > 1인 경우, 배열을 크기가 2N-1 × 2N-1로 4등분 한 후에 재귀적으로 순서대로 방문한다.
다음 예는 22 × 22 크기의 배열을 방문한 순서이다.

N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.
다음은 N=3일 때의 예이다.

입력
첫째 줄에 정수 N, r, c가 주어진다.
출력
r행 c열을 몇 번째로 방문했는지 출력한다.
제한
- 1 ≤ N ≤ 15
- 0 ≤ r, c < 2N
2. 코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static int[][] arr;
static int count = 0;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int m = (int) Math.pow(2, N);
arr = new int[m][m];
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
dp(0, 0, m - 1, m - 1);
System.out.println(arr[r][c]);
}
static void dp(int startRow, int startCol, int endRow, int endCol) {
int rowLen = endRow - startRow;
int colLen = endCol - startCol;
if (rowLen == 1 && colLen == 1) {
arr[startRow][startCol] = count++;
arr[startRow][endCol] = count++;
arr[endRow][startCol] = count++;
arr[endRow][endCol] = count++;
} else {
dp(startRow, startCol, startRow + rowLen / 2, startCol + colLen / 2);
dp(startRow, startCol + colLen / 2 + 1, startRow + rowLen / 2, endCol);
dp(startRow + rowLen / 2 + 1, startCol, endRow, startCol + colLen / 2);
dp(startRow + rowLen / 2 + 1, startCol + colLen / 2 + 1, endRow, endCol);
}
}
}
3. 해설
- 동적 계획법으로 모든 배열의 값을 정하는 방식
- 문제점 : 해당하는 좌표의 값만 필요한데 불필요하게 모든 값을 초기화 하느라 배열 메모리를 너무 많이 잡아먹는다
→ 위치에 따라 시작 값을 받아와서 배열 없이 값을 구하도록 한다.
4. 다른 풀이
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
static int count = 0;
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
int m = (int) Math.pow(2, N);
int r = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
System.out.println(find(0,0, m, r, c));;
}
static int find(int startRow, int startCol, int size, int targetRow, int targetCol) {
if (size == 1) {
return count;
}
int newSize = size / 2;
int areaCount = newSize * newSize;
// 1번 사분면
if (targetRow < startRow + newSize && targetCol < startCol + newSize) {
return find(startRow, startCol, newSize, targetRow, targetCol);
}
// 2번 사분면
else if (targetRow < startRow + newSize && targetCol >= startCol + newSize) {
count += areaCount;
return find(startRow, startCol + newSize, newSize, targetRow, targetCol);
}
// 3번 사분면
else if (targetRow >= startRow + newSize && targetCol < startCol + newSize) {
count += 2 * areaCount;
return find(startRow + newSize, startCol,newSize, targetRow, targetCol);
}
// 4번 사분면
else {
count += 3 * areaCount;
return find(startRow + newSize, startCol + newSize, newSize, targetRow, targetCol);
}
}
}
- 타겟 좌표가 현재 사이즈 기준으로 어느 위치에 속하는지 확인 한후 사분면에 따라 count에 적절한 값을 더한 후 찾는다.
'Java > 알고리즘(코테)' 카테고리의 다른 글
백준 22351번: 수학은 체육과목 입니다 3 (1) | 2024.11.16 |
---|---|
백준 14940번 : 쉬운 최단거리 (1) | 2024.11.09 |
백준 11724번 : 연결 요소의 개수 (유니온 파인드 알고리즘) (0) | 2024.10.15 |
백준 30504번 : 세과영엔 슬픈 전설이 있어 (2) | 2024.10.13 |
백준 2805번 : 나무 자르기 (0) | 2024.10.09 |