알고리즘/백준
6549 히스토그램에서 가장 큰 직사각형
흰싸라기
2022. 3. 21. 01:14
백준 6549 히스토그램에서 가장 큰 직사각형 : https://bit.ly/3Jtkc86
6549번: 히스토그램에서 가장 큰 직사각형
입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤
www.acmicpc.net
[코드 작성 전 정리]
우선 분할 정복으로 풀 것이기 때문에 재귀함수로 구현
필요한 것
① 반(left, right) 나누기
- return max, 높이 정보 필요 (높이는 참조로 전달)
② 합치기
- left, right 중 더 낮은 높이를 기준으로 합치기
③ 합칠 때 겹치는 부분 생각하기
- 겹치는 부분 기준으로 왼쪽, 오른쪽으로 확장하며 max값 계산하기
[문제풀이]
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
ll area(ll* his, int size, int x, ll& h) {
if (size == 1) {
h = his[x];
return his[x];
}
else {
// 나누기
ll lh, rh;
int ln = size / 2;
int rn = size - ln;
ll lmax = max(area(his, ln, x, lh), area(his, rn, x + ln, rh));
//합치기
h = min(lh, rh);
ll tmax = h * size;
// 겹치는 부분 확인
int lx = x + ln - 1;
int rx = lx + 1;
ll th = min(his[lx], his[rx]);
tmax = max(tmax, th * 2);
while (lx > x || rx < x + size - 1) {
if (lx > x && (rx == x + size - 1 || his[lx - 1] > his[rx + 1])) {
// 왼쪽으로 확장 가능 && (오른쪽 끝까지 도달||오른쪽 확장 높이보다 왼쪽 확장 높이가 더 큰 경우)
lx--;
th = min(th, his[lx]);
}
else {
rx++;
th = min(th, his[rx]);
}
tmax = max(tmax, th * (rx - lx + 1));
}
return max(tmax, lmax);
}
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
while (true) {
int n;
cin >> n;
if (n == 0) break;
ll* his = new ll[n];
int k;
for (int i = 0; i < n; i++) {
cin >> k;
his[i] = k;
}
ll h;
ll hmax = area(his, n, 0, h);
cout << hmax << "\n";
delete[] his;
}
return 0;
}
ll area(ll* his, int size, int x, ll& h) | |
ll* his | 히스토그램 높이를 저장하는 배열 |
int size | 현재 확인하고 있는 범위 |
int x | 현재 확인하고 있는 범위의 첫번째 인덱스 값 |
ll& h | 현재 범위의 최소 높이 값 (전달을 위해 참조로 사용) |
while문 | 겹치는 부분 기준으로 확장하기 위한 반복문 고려할 점 ① 현재 범위(x~x+size-1)를 벗어나지 않으면서 확장할 수 있는가 ② 왼쪽, 오른쪽 중 높이가 더 큰 쪽으로 확장할 것 ③ 한 쪽 확장이 끝나면 높이 상관없이 나머지 방향으로 확장할 것 |
*주의할 점
long long int 사용하기
[comment]
처음 분할정복 생각한게 맞았는데 괜히 다르게 푼다고 시간이 더 오래걸려서 아쉬운 문제
문제 자체는 그냥 기본 분할정복에서 겹치는 부분 고려하는 것만 추가된 느낌
추가로, 처음에 while문 작성할 때 현재 범위 한정으로 확인하고 안하고가 시간초과에 영향을 줘서 처음부터 생각하지 못한것도 아쉬움
이렇게 푼 방법 외에도 세그멘트 트리, 스택 등의 방식이 있어 추가로 풀어보는 것도 좋을 듯 싶다.