일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 백준 알고리즘
- supervised learning
- 인공지능
- 딥러닝공부
- 머신러닝공부
- acmicpc.net
- Gradient Descent
- Python강의
- feature scaling
- python강좌
- 비지도학습
- 자바시작하기
- 지도학습
- C언어
- 파이썬강좌
- 머신러닝
- 비용함수
- 효묘블로그
- c언어 오목
- 자바
- 경사하강법
- JAVA강좌
- 딥러닝
- 파이썬강의
- 머신러닝 강의
- java
- unsupervised learning
- 선형회귀
- 머신러닝 강좌
- 자바강좌
Archives
- Today
- Total
컴공과컴맹효묘의블로그
백준[1725] 히스토그램 본문
반응형
https://www.acmicpc.net/problem/1725
입력이 10만이라, O(N^2)은 시간 내 풀이가 불가능합니다.
"이 직사각형의 밑변은 항상 히스토그램의 아랫변에 평행하게 그려져야한다." 에서 아래쪽 밑변은 히스토그램의 아랫변과 겹치게 그리는 것이 항상 최대이고, 위쪽 밑변은 직사각형이 포함하는 막대들의 높이 중 최소인 막대의 윗변과 겹쳐야합니다.
O(NlogN)가 걸리는 분할정복으로 풀어봤습니다.
하나의 히스토그램을 절반으로 잘라서 왼쪽의 최대와 오른쪽의 최대, 그리고 중간을 포함하는 큰 히스토그램의 최대를 구하여 비교합니다.
중간을 포함하는 큰 히스토그램은 투 포인터로 O(N)이 걸립니다.
left와 right를 각각 mid, mid+1로 초기화 하고 left-1, right+1의 높이를 비교하여 큰 쪽으로 확장하면서 넓이를 구합니다. 그리고 각각 구한 넓이의 최대값을 구합니다.
좀 더 자세히 설명하자면,
인덱스가 mid, mid+1인 두 막대를 포함하는 넓이를 구하기 때문에 직사각형의 확장은 왼쪽 혹은 오른쪽으로밖에 하지 못 합니다.
이 때 왼쪽이나 오른쪽 어디로 확장해야하는지 선택해야하는데, 그 전에 직사각형의 넓이는 밑변*높이 입니다. 왼쪽 혹은 오른쪽 확장은 둘 다 밑변이 1 증가하므로 높이가 최대한 줄어들지 않는 쪽으로 선택해야한다. 즉, left - 1과 right + 1의 높일를 비교하여 더 높은쪽을 선택하여 확장해야합니다.
#include <iostream>
#include <algorithm>
#include <vector>
#include <math.h>
#define lld long long
using namespace std;
int n;
vector<int> v;
lld solve(int start, int end) {
if(start == end) {
return v[start];
}
if(start > end) {
return 0;
}
int mid = (start + end) / 2;
lld left_area = solve(start, mid); // 왼쪽 히스토그램
lld right_area = solve(mid + 1, end); // 오른쪽 히스토그램
lld mid_area = 0;
lld max_area = max(left_area, right_area);
int left = mid;
int right = mid + 1;
int height = min(v[left], v[right]);
mid_area = (right-left+1) * height;
// 중간(mid, mid+1) 두 개의 막대를 포함하는 가장 큰 넓이. 어느 한 쪽이 끝에 도달할때까지 반복
while(start < left && right < end) {
if(v[left-1] < v[right+1]) {
right++;
height = min(height, v[right]);
} else {
left--;
height = min(height, v[left]);
}
lld area = (right-left+1) * height;
mid_area = max(mid_area, area);
}
lld area = 0;
// 왼쪽 혹은 오른쪽에 먼저 도달했을 경우 반대편을 끝까지 확장하기
if(start == left) {
while(right < end) {
right++;
height = min(height, v[right]);
area = (right-left+1) * height;
mid_area = max(mid_area, area);
}
} else {
while(left > start) {
left--;
height = min(height, v[left]);
area = (right-left+1) * height;
mid_area = max(mid_area, area);
}
}
return max(mid_area, max_area);
}
int main()
{
ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> n;
v = vector<int>(n);
for(int i = 0; i < n; i++) {
cin >> v[i];
}
lld ans = solve(0, n-1);
cout << ans << endl;
return 0;
}
반응형
'알고리즘 > 백준' 카테고리의 다른 글
백준[1241] 머리 톡톡 (0) | 2025.05.04 |
---|---|
백준[2230] 수 고르기 (0) | 2022.07.24 |
백준[13913]숨바꼭질 4 (0) | 2022.07.16 |
백준[14728] 벼락치기 (1) | 2022.07.16 |
백준[1406] 에디터 (0) | 2022.05.26 |
Comments