참고자료 (더 설명이 잘 되어있는 글들)
[백준] 6549번 : 히스토그램에서 가장 큰 직사각형 - JAVA [자바]
[BAEKJOON] 6549 히스토그램에서 가장 큰 직사각형
심플하다.
위와 같이 히스토그램이 주어졌을 때, 히스토 그램 내부에서 그릴 수 있는 가장 큰 직사각형을 찾으면 된다.
예제로 주어진 히스토그램 기준 분할과 정복으로 mid 기준 왼쪽의 히스토그램을 다음과 같이 탐색할 수 있다.
그리다가 순서가 꼬여서 뒤죽박죽이 되었지만 (아마) 모든 경우의 수를 그렸을 것이다.
0 ~ 6부터 시작해 mid 3 -> 1 까지 수행했을 때의 탐색할 수 있는 직사각형이다.
그런데 잘 보면 빠져있는 사각형이 있다.
바로 두번째 기준점(mid)이었던 1을 횡단하는 사각형이다.
경우의 수를 따지진 않았지만 첫번째 기준점 3을 횡단하는 아래와 같은 사각형의 넓이 역시 고려하지 못할 것이다.
때문에 분할과 정복이 고려하지 못하는 mid 지점부터 좌우로 탐색하면서 최대 넓이를 구해야한다.
뻗어나가는 경우의 수는 왼쪽과 오른쪽 2가지인데, 최대 넓이를 구해야하므로 왼쪽과 오른쪽 중 히스토그램의 넓이가 높은 곳으로 뻗어나가면 된다.
left -= 1
)left -= 1
)left -= 1
)이렇게하면 모든 경우의 수를 시간복잡도 O(NlogN)으로 고려하여 답을 구할 수 있다.
※ 사실 저도 제대로 이해 못한 상태로 푼거라 주석을 따로 못달았습니다.
import sys
input = sys.stdin.readline
def devide(left, right):
global hist
if left == right:
return hist[left]
mid = (left + right) // 2
lmid, rmid = mid, mid+1
area = max(devide(left, lmid), devide(rmid, right))
height = min(hist[lmid], hist[rmid])
area = max(area, height * 2, hist[lmid], hist[rmid])
while (left < lmid or rmid < right):
if (rmid < right and (lmid <= left or (hist[lmid-1] < hist[rmid+1]))):
rmid += 1
height = min(height, hist[rmid])
else:
lmid -= 1
height = min(height, hist[lmid])
area = max(area, height * (rmid-lmid+1))
return area
while True:
inputs = list(map(int, input().split()))
if inputs == [0]:
break
answer = 0
n = inputs[0]
hist = inputs[1:]
print(devide(0, n-1))
분할과 정복 알고리즘이 내 약점인지 골드 하위만 되어도 몇시간을 붙잡아야 겨우겨우 풀고, 골드 중상위부터는 아무리 머리를 싸매도 풀이가 안나오고 있다.
익숙해지기 위해 결국 풀이를 찾고 정리하면서 풀고 있지만... 아직은 딱히 실력이 늘었다고 생각하지 않는다.
코드 플러스가 제공하는 분할과 정복 연습문제도 얼마 남지 않았는데, 아무래도 다른 연습문제들을 찾아서 더 풀어봐야겠다.