ABOUT ME

Today
Yesterday
Total
  • 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문 작성할 때 현재 범위 한정으로 확인하고 안하고가 시간초과에 영향을 줘서 처음부터 생각하지 못한것도 아쉬움

    이렇게 푼 방법 외에도 세그멘트 트리, 스택 등의 방식이 있어 추가로 풀어보는 것도 좋을 듯 싶다. 

    '알고리즘 > 백준' 카테고리의 다른 글

    1260 DFS와 BFS  (0) 2022.03.25
    2805 나무 자르기  (0) 2022.03.23
    1920 수 찾기(이분탐색)  (0) 2022.03.23
    2630 색종이 만들기  (0) 2022.03.17
    1068 트리  (1) 2022.03.13

    댓글

Designed by Tistory.