1074 Z
문제
한수는 크기가 2N × 2N인 2차원 배열을 Z모양으로 탐색하려고 한다.
예를 들어, 2×2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.
N > 1인 경우, 배열을 크기가 2^(N-1) × 2^(N-1)로 4등분 한 후에 재귀적으로 순서대로 방문한다.
다음 예는 2^2 × 2^2 크기의 배열을 방문한 순서이다.
N이 주어졌을 때, r행 c열을 몇 번째로 방문하는지 출력하는 프로그램을 작성하시오.
다음은 N=3일 때의 예이다.
입력
첫째 줄에 정수 N, r, c가 주어진다.
출력
r행 c열을 몇 번째로 방문했는지 출력한다.
제한
- 1 ≤ N ≤ 15
- 0 ≤ r, c < 2^N
예제 입력 1
예제 출력 1
예제 입력 2
예제 출력 2
예제 입력 3
예제 출력 3
예제 입력 4
예제 출력 4
예제 입력 5
예제 출력 5
예제 입력 6
예제 출력 6
Solution
펼쳐보기
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
| import java.util.*
private var N: Int = 0 private var R: Int = 0 private var C: Int = 0
fun main() { input() solve() }
private fun input() = with(Scanner(System.`in`)) { N = nextInt() R = nextInt() C = nextInt() }
private fun solve() { val side = 2.pow(N)
divide(side, R, C) println(conquer(0)) }
private fun divide(side: Int, row: Int, column: Int) { if (side == 1) { return }
if (row < side / 2 && column < side / 2) { conquer(0) divide(side / 2, row, column) } else if (side / 2 in (row + 1)..column) { conquer(side * side / 4) divide(side / 2, row, column - side / 2) } else if (side / 2 in (column + 1)..row) { conquer(side * side / 4 * 2) divide(side / 2, row - side / 2, column) } else { conquer(side * side / 4 * 3) divide(side / 2, row - side / 2, column - side / 2) } }
private var result = 0 private fun conquer(coefficient: Int): Int { result += coefficient return result }
fun Int.pow(n: Int): Int { return Math.pow(this.toDouble(), n.toDouble()).toInt() }
|
Point of Thinking
- 분할 정복의 대표적인 예시인 색종이 자르기의 응용인 버전이다.
- 주어진 배열을 기준으로 주어진 좌표가 몇 사분면에 위치하는지 분기하면서 계속해서 분할해나간다.
- 분할하면서 순회할 필요가 없는 사분면의 면적값(=순회 횟수)를 더해나가면서 더해나간다(=정복).
- N이 1일 될때까지 순회 후 정복한 값을 출력하면 Accpeted.
References