일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- parametric search
- 최장증가수열
- 2493 백준
- 서로소 집합
- 그래프이론
- 브루트포스
- 결정문제
- disjoint set
- 이분탐색
- 최장길이바이토닉수열
- 뒤집기 3
- 백준 1464
- boj 1464
- Lis
- 이분 탐색
- bfs
- DP
- 재귀
- 깊이 우선 탐색
- 백준 뒤집기 3
- 비트마스킹
- 구현
- 1939백준
- 그래프 이론
- union find
- 결정 문제
- 분할정복
- 그래프탐색
- 패스트캠퍼스
- 그래프 탐색
- Today
- Total
알고리즘 문제풀이
[BOJ] 1074번 : Z 본문
문제
한수는 2차원 배열 (항상 2^N * 2^N 크기이다)을 Z모양으로 탐색하려고 한다. 예를 들어, 2*2배열을 왼쪽 위칸, 오른쪽 위칸, 왼쪽 아래칸, 오른쪽 아래칸 순서대로 방문하면 Z모양이다.

만약, 2차원 배열의 크기가 2^N * 2^N라서 왼쪽 위에 있는 칸이 하나가 아니라면, 배열을 4등분 한 후에 (크기가 같은 2^(N-1)로) 재귀적으로 순서대로 방문한다.
다음 예는 2^2 * 2^2 크기의 배열을 방문한 순서이다.

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

입력
첫째 줄에 N r c가 주어진다. N은 15보다 작거나 같은 자연수이고, r과 c는 0보다 크거나 같고, 2^N-1보다 작거나 같은 정수이다
출력
첫째 줄에 문제의 정답을 출력한다.
예제 입력 1
2 3 1
예제 출력 1
11
예제 입력 2
3 7 7
예제 출력 2
63
출처
알고리즘 분류
- 분할정복
- 재귀
접근 방법
최대 N이 15 가 될 수 있으므로, 직접 2차원 배열을 만들고 for문을 통해 순회하며 Numbering하는 것은 불가능하다. O(N^2)
문제를 자세히 보면 해당하는 r,c가 나올 때 까지, 사각형내에서 4조각으로 쪼개서 탐색하는 부분문제로 쪼갤 수 있다는 것을 알아차릴 수 있다.
이는 분할정복에서 큰 문제를 작은 문제들로 쪼개는 단계와 같다는 것을 알 수 있다.
더 이상 나눌 수 없는 작은 문제는 크기가 1인 사각형이 나왔을 때 이므로, 그런 조각이 나올 때 까지의 numbering을 해주면 되겠다.
( skip한 영역의 개수 * 해당 영역의 크기 만큼을 탐색이 완료 될 때 까지 더해주면 우리가 원하는 정답을 찾을 수 있다. )
분할 하는 방법은 큰 사각형의 가로를 반으로 나누는 부분 ~ 세로를 반으로 나누는 부분을 직선으로 그으면 + 모양으로 분할 되는데 한 변의 길이는 2의 K제곱 꼴의 형태이므로 분할 된 4개의 사각형의 길이는 모두 동일하다.
위 방법을 적용하면 subProblem에서도 루프불변성을 유지함을 알 수 있다.
소스 코드
#include <iostream>
#include <cmath>
using namespace std;
long long answer = 0 ;
int N,R,C;
void find(int n, int sy, int sx){
if( n == 0 || ( sy == R && sx == C )){
return ;
}
int size = pow(2,n-1);
// 왼쪽 상단
if( sy <= R && R < sy+size && sx <= C && C < sx + size ){
find(n-1, sy, sx );
}
// 오른쪽 상단
else if( sy <= R && R < sy+size && sx+size <= C && C < sx + 2*size ){
answer += size*size;
find( n-1, sy, sx+size );
}
// 왼쪽 하단
else if( sy+size <= R && R < sy + 2*size && sx <= C && C < sx + size ){
answer += 2*size*size;
find( n-1, sy+size, sx );
}
// 오른쪽 하단
else{
answer += 3*size*size;
find( n-1, sy+size, sx+size );
}
return;
}
int main(void){
cin >> N >> R >> C;
// 2차원 배열은 항상 2^N * 2^N의 모양
// 재귀적으로 1개의 칸이 나올 때 까지 4분할을 한다.
find(N,0,0);
cout << answer ;
return 0;
}
'자료구조 + 알고리즘 > [BOJ]' 카테고리의 다른 글
[BOJ] 11055번 - 가장 큰 증가 부분 수열 (0) | 2020.11.12 |
---|---|
[BOJ] 2631번 - 줄 세우기 (0) | 2020.11.12 |
[BOJ] 3190번 - 뱀 (0) | 2020.11.12 |
[BOJ] 18119번 - 단어 암기 (0) | 2020.11.11 |
[BOJ] 2206번 - 벽 부수고 이동하기 (0) | 2020.11.11 |