cs
CS/PS

[BOJ] 1725번 : 히스토그램

https://www.acmicpc.net/problem/1725

 

1725번: 히스토그램

첫 행에는 N (1 ≤ N ≤ 100,000) 이 주어진다. N은 히스토그램의 가로 칸의 수이다. 다음 N 행에 걸쳐 각 칸의 높이가 왼쪽에서부터 차례대로 주어진다. 각 칸의 높이는 1,000,000,000보다 작거나 같은

www.acmicpc.net

 

divide and conquer로 해결할 수 있는 문제이다. 

 

start에서 end까지의 부분 히스토그램을 보았을 때, 그 안에서 만들 수 있는 직사각형의 최대 넓이는 세 경우 중 하나에서 구할 수 있다. 편의상 mid = (start+end)/2 로 정의한다.

 

1. start ~ mid까지의 부분 히스토그램 중 최대 넓이

2. mid+1 ~ end까지의 부분 히스토그램 중 최대 넓이

3. mid와 mid+1을 포함하는 부분 히스토그램 중 최대 넓이(중간에 걸쳐 있는 것)

 

1과 2는 재귀로 구하면 되고, 3번이 문제인데, 3번은 가운데 두 막대그래프에서 시작해서 하나씩 확대해가면서 최대 넓이를 갱신하면 된다. 맨 처음 min(h[mid], h[mid+1])을 height로, 2를 width로 두어 넓이를 계산하여 최대 넓이로 설정한다. 그 다음 left-1과 right+1을 확인하여 더 높이가 높은 쪽으로 한 칸 확장시켜 다시 넓이를 확인하면 된다.

 

이것이 가능한 이유는 높이가 더 높은 쪽으로 확장시키는 쪽이 항상 더 넓은 넓이를 확인할 수 있게 해 주기 때문이다. 만약 높이가 더 낮은 쪽으로 하는 것이 최종적으로 더 넓은 넓이가 되더라도, 그 쪽은 나중에 계산해도 그 값을 얻을 수 있다. 높은 쪽을 먼저 다 하고 나서 낮은 쪽으로 오면 되기 때문이다.

 

시간복잡도는 3번이 단계마다 N번 소요되고, level이 logN개 있으므로 NlogN이다.

 

 

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
61
62
63
64
65
#include <stdio.h>
#include <algorithm>
 
using namespace std;
 
const int maxN = 100500;
 
int c, n, h[maxN];
 
int maxMidCross(int start, int end) {
    
    int maxArea = -1;
    int mid = (start+end)/2;
    int left = mid;
    int right = mid+1
    int height = min(h[left], h[right]);
    maxArea= (right-left+1)*height;
    
    while(left > start || right < end) {
        
        if(left == start) right++;
        else if(right == end) left--;
        else {
            if(h[left-1> h[right+1])    left--;
            else right++;
        }
        height = min(height, h[left]);
        height = min(height, h[right]);
        maxArea = max(maxArea, (right-left+1)*height);
        
        
    }
    
    return maxArea;
    
}
 
int maxRect(int start, int end) {
    
    int maxArea = -1;
    int mid = (start+end)/2;
    if(start==endreturn h[start];
    
    else { 
        
        maxArea = max(maxArea, maxRect(start, mid));
        maxArea = max(maxArea, maxRect(mid+1end));
        maxArea = max(maxArea, maxMidCross(start, end));
        
    }
    return maxArea;
    
}
 
int main ( void )  {
    
    scanf("%d"&n);
    for(int j = 0; j < n; j++) {
        scanf("%d"&h[j]);
    }
        
    printf("%d\n", maxRect(0, n-1));
 
    
}
cs

 

'CS > PS' 카테고리의 다른 글

[BOJ] 1028번 : 다이아몬드 광산  (0) 2021.07.05
[BOJ] 1005번 : ACM craft  (0) 2021.07.04
[BOJ] 1074번 : Z  (0) 2021.07.03
[BOJ] 1449번 : 수리공 항승  (0) 2021.07.02
[Algospot] 소풍(PICNIC)  (0) 2021.06.16